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
.
我不明白 .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
.