【问题标题】:How does the `asm()` function works in C language?`asm()` 函数在 C 语言中是如何工作的?
【发布时间】:2017-02-12 17:30:18
【问题描述】:

我正在学习操作系统开发,当然是初学者。我想在实模式环境中构建我的系统,这是一个使用 C 语言的 16 位环境。

在 C 语言中,我使用函数asm() 将代码转换为 16 位,如下所示:

asm(".code16")

在 GCC 的语言中生成 16 位可执行文件(虽然不完全是)。

问题:

假设我有两个头文件head1.hhead2.h 和一个main.c 文件。 main.c文件内容如下:

asm(".code16");
#include<head1.h>
#include<head2.h>
int main(){
  return 0;
}

现在,由于我使用生成 16 位可执行文件的命令开始我的代码,然后包含 head1.hhead2.h,我是否需要在我要创建的所有头文件中执行相同的操作? (或)将asm(".code16"); 行添加一次就足够了吗?

操作系统:Ubuntu

编译器:Gnu CC

【问题讨论】:

  • 我建议你不要使用 gcc 编译 16 位代码。你使用的是一个会导致一堆问题的杂物。

标签: gcc assembly operating-system kernel bootloader


【解决方案1】:

回答您的问题:asm 块出现在翻译单元的开头就足够了。
所以在开头放一次就可以了。

但您可以做得更好:您可以完全避免它并改用the -m16 command line option (available from 5.2.0)

但你可以做得更好:你可以完全避免它。


-m16.code16的作用是使32位代码在实模式下可执行,不是产生实模式代码。

16.c

int main()
{
   return 4;
}

提取原始 .text

>gcc -c -m16 16.c
>objcopy -j .text -O binary 16.o 16.bin
>ndisasm 16.bin

我们得到

00000000  6655              push ebp
00000002  6689E5            mov ebp,esp
00000005  6683E4F0          and esp,byte -0x10
00000009  66E800000000      call dword 0xf
0000000F  66B804000000      mov eax,0x4
00000015  66C9              o32 leave
00000017  66C3              o32 ret

这只是用操作数大小前缀填充的 32 位代码。
On a real pre-386 machine this won't work as the 66h opcode is UD


有一些旧的 16 位编译器,例如 Turbo C1,可以正确解决实模式应用程序的问题。

或者,尽快切换到保护模式或考虑使用 UEFI。


1 可在线获取。这个编译器和我一样老!

【讨论】:

【解决方案2】:

head1.hhead2.h中都不需要添加asm("code16")

主要原因是 C 预编译器的工作方式。它替换了main.c内的head1.hhead2.h的内容。

请查看How `#include' Works了解更多信息。

希望对你有帮助!

最好的问候,

米格尔·安赫尔

【讨论】:

    猜你喜欢
    • 2014-12-29
    • 1970-01-01
    • 2014-02-09
    • 2016-11-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    相关资源
    最近更新 更多