4

我正在尝试在汇编中为 x86-64 编写一些特殊的例程(即使 x86 示例也可以)。问题:我的即时信息仅在链接时解决。

例如,

addq $Label2-Label1, %rax

会将两个标签/符号之间的差异添加到 rax。不幸的是,因为 GNU Assembler 只执行一次(我不知道为什么,即使是像 FASM 这样的开源汇编程序也执行多次),它无法解决这些问题,因此它会让链接器执行此操作。

不幸的是,它将为链接器保留 4 个字节(32 位立即数),这不是我想要的,因为标签的差异始终在 -128 到 +127 范围内。

我的问题,我如何强制或指定指令应该有一个 8 位立即数?比如,这里的语法是什么?在 AT&T 语法或 Intel 中,两者都可以。例如,在 NASM 中,您可以:

add rax, byte Label2-Label1

指定 8 位立即数。但是如何在 GAS 中做到这一点?即使它不知道立即数本身,强制它使用 8 位立即数的语法是什么......出于特定原因,我最好在 GAS 中使用它,所以请不要告诉我使用 NASM 作为回答!

编辑:对不起,我忘了提,是的,这是一个“前向参考”。两个标签都是在指令之后定义的,这就是 GAS 无法解决它们的原因,我认为这是一个重定位,但是使用 '.byte label2-label1' 确实有效,因为我已经测试过了,所以我知道它应该是可能的如果它有一些语法......

4

2 回答 2

4

如果Label1Label2在同一个源文件中,那么问题似乎与链接器无关(在这种情况下 GAS 不会生成任何重定位),也不是因为 GAS 是一次性汇编器。它足够聪明,可以生成正确大小的分支,这是一个类似的问题。

问题归结为 GAS 不够聪明,无法在跳转和分支以外的情况下选择正确大小的指令,并且无法明确指定操作数的大小。“.d8”位移后缀几乎是您想要的语法,但从技术上讲,您并没有使用位移。但它无论如何都不起作用,因为leal.d8 Label2-Label1(%eax),%eax它不起作用,尽管实际上正在使用位移。

所以这真的只剩下一种选择,手工组装操作码。例如在 32 位汇编中:

.byte 0x83, 0xC0, (label2 - label1)

至于为什么 GAS 只是一个一次性的汇编器,而其他汇编器通常不会做很多事情,答案很简单。它主要用于组装 GCC 的输出。

于 2014-08-20T23:31:42.983 回答
1

Unfortunately, this is not possible; because GAS doesn't figure out what the difference should be, it has no choice but to leave a 4-byte relocation entry for the linker to resolve. This is because the object file format (which is more than likely ELF) doesn't support 8-bit relocations - it only supports 32-bit relocations. Thus, it will always use a 32-bit immediate.

于 2014-08-20T21:59:01.890 回答