【问题标题】:Can't force the use of 64-bit registers in GCC inline assembly不能在 GCC 内联汇编中强制使用 64 位寄存器
【发布时间】:2017-12-23 18:50:41
【问题描述】:

我正在尝试使用 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 位寄存器?

【问题讨论】:

  • 大多数 32 位指令的结果是零扩展为完整的 64 位宽度。 mov 指令绝对是这样,因此“mov eax, 60”和“mov rax, 60”对处理器的影响应该相同。
  • 超越其他 cmets 并回答。我假设您正在使用高于-O0 的优化级别进行编译。您可能会发现在优化级别 -O0 可能使用了 RAX。当对编译器进行优化时,可能会使用这样一个事实,即当操作的目标是 32 位寄存器时,高 32 位变为 0。我敢打赌,如果您进行了一个名为 syscall(0x6060606060606060, 0x7fffffffffffffff); 的实验,那么完整的寄存器 RAX 和 RDX 将被使用,因为这些值超过了 32 位可以表示的值。

标签: c gcc x86-64 inline-assembly


【解决方案1】:

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

mov eax, 60

Writing to EAX always clears the upper 32-bit half of the 64-bit register。这不像 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
  • 为什么?这是完全等价的。
  • @OdnetninI 我认为 gcc 根本不会发出这条指令。
  • 只是对阅读本文的任何人的评论,内联汇编代码使用 intel 语法(非默认),因此如果想使用此示例,他们可能会考虑将 -masm=intel 传递给 GCC.
  • @OdnetninI:一些汇编程序(例如 NASM)甚至会为您优化 mov rax, 60mov eax, 60,因为它们对架构状态的影响几乎相同(除了 RIP,因为要多占用 2 个字节) .不过,YASM 不会,GNU as 也不会。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-11
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多