GNU 汇编程序指令 .code16 的用途是什么?

What is the purpose of GNU assembler directive .code16?

我不明白 .code16 或其他 .code* 指令的实际用法。我从 this question on Whosebug

的答案中了解到的内容

当有人在他们的汇编代码中定义 .code16 并执行以下操作时:

$ gcc -c -m32 -o main.o main.s

它忽略了 .code16 并且输出程序集在 32 位平台上意味着 运行。如果有人没有指定 -m 标志,它似乎将 gcc 配置的那个作为默认值,具体取决于主机。因此,总而言之,.code* 指令总是被忽略并被 -m 标志取代。

如果我的理解有误,有人可以纠正我吗?当我使用 .code16 时是什么情况,因为我总是可以使用 -m16.code* 来定义它无论如何都会被忽略,具体取决于目标模式。

.code16(或其他)是否仅在数据无法放入 16 位寄存器时抛出错误,否则它们将保持休眠状态?

您通常使用 .code16.code32.code64 的唯一原因是在内核或引导加载程序中 当您想要机器代码时对于同一文件中的不同模式。例如以实模式 (.code16) 启动的引导加载程序可以启用保护模式并远跳 (ljmp) 到 32 位代码段。您想在该代码块之前使用 .code32

如果这不是您正在做的,请不要使用它们。

在其他情况下使用它们只会让你搬起石头砸自己的脚,将 16 位机器代码放入 32 位或 64 位 ELF 可执行文件中,这样你就会 运行time failure 而不是捕获构建时的错误。 (例如,因为 push %eax 在 64 位模式下无效)。不要将 .code32 放在 32 位程序的顶部;使用 assemble with gcc -m32.

的注释

这些指令告诉 assembler CPU 在解码这些指令时将处于什么模式。所以它知道默认的操作数大小和地址大小,以及使用 32 位或 16 位寄存器的指令是否需要前缀。

例如,在 32 位模式下 mov %eax, (%ecx) assemble 到 89 01

但在 .code16 之后,它 assemble 变为 67 66 89 01

如果您随后将其作为 32 位机器代码排除assemble,则它是 67 66 89 01 mov %ax, (%bx,%di)(因为 ModRM 在 16 与 32 和 64 位模式下的内存操作数不同)。


您通常不会手动使用 .code16。您可以使用 gcc -m16 foo.c 让 GCC 在文件顶部插入 .code16gcc,这样您就可以在 16 位模式下 运行 它,即使它仍然使用 32 位操作数-大小和地址大小(需要 386 兼容 CPU)。


如果您想在普通的 64 位程序中包含 32 位或 16 位机器代码作为数据,例如因此您的程序可以将其写入文件或使用它修改 运行ning 进程,您也可以使用 .code32.code16.