无法在GCC内联汇编中强制使用64位寄存器

6

我正在尝试使用GCC内嵌汇编来做一些事情,比如进行系统调用,但是我想强制使用64位寄存器(rax、rdi、rsi等)而不是32位寄存器(eax、edi等),但是我尝试了很多方法,都没有成功。

void syscall(uint64_t arg1, uint64_t arg2) {
   // arg1 -> rax        arg2 -> rdi
   __asm__("syscall" : : "a" (arg1), "D" (arg2));
}

当我编译时,我得到以下结果:
mov eax, 60
syscall

我在一个函数中,因此“edi”是从参数中获取的,但正如您所看到的是“eax”,我想使用rax。

如何强制使用64位寄存器而不是32位寄存器?


2
大多数32位指令的结果都会被零扩展到完整的64位宽度。这在mov指令中绝对是正确的,因此“mov eax,60”和“mov rax,60”应该对处理器具有相同的影响。 - David
除了其他评论和答案之外,我假设您正在使用高于-O0的优化级别进行编译。在优化级别为-O0时,您可能会发现_RAX_被使用。当编译器打开优化时,它可能利用以下事实:当操作的目标是32位寄存器时,上32位变成0。我敢打赌,如果您进行一个实验,调用syscall(0x6060606060606060, 0x7fffffffffffffff);,那么完整的寄存器_RAX_和_RDX_将被使用,因为这些值超过了32位可以表示的范围。 - Michael Petch
1个回答

10

这实际上将RAX寄存器设置为60:

mov eax, 60

写入 EAX 寄存器总是会清除 64 位寄存器的高 32 位,这与 AH 和 AL 不同,它们的写入保留了寄存器的其余部分。

如果你一定要移动到 RAX,则需要使用以下方法:

static inline __attribute__ ((always_inline)) void
syscall(uint64_t arg1, uint64_t arg2)
{
   __asm__("mov rax, %0; syscall" : : "i" (arg1), "D" (arg2) : "rax");
}
请注意,gas 仍将将此操作汇编为 32 位立即移动。

我知道,但我想强制gcc放置mov rax, 60 - Eduardo José Gómez Hernández
3
为什么?这完全等同。 - Jester
1
@OdnetninI 我认为gcc根本不会发出这个指令。 - fuz
2
对于阅读此内容的任何人,我只想说一句评论:内联汇编代码使用英特尔语法(而不是默认语法),因此如果要使用此示例,则可能需要考虑将“-masm = intel”传递给GCC。 - Michael Petch
@OdnetninI:有些汇编器(例如NASM)甚至会为您优化mov rax,60mov eax,60,因为它们在架构状态上具有完全相同的效果(除了RIP因多占用2字节)。 YASM不会这样做,GNU as也不会。 - Peter Cordes
有些汇编器允许您在立即数很小的情况下强制使用mov imm64,例如nasm中的mov rax, strict 0。请参见What methods can be used to efficiently extend instruction length on modern x86? - phuclv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接