【问题标题】:Pass arguments in edi/esi in SysV ABI在 SysV ABI 中的 edi/esi 中传递参数
【发布时间】:2020-11-27 12:43:15
【问题描述】:

我想用 SysV ABI x86_64 程序集编写程序,到目前为止,我已经非常随机地在寄存器中传递了参数。

但我刚刚在这个论坛上看到,有一个标准。我们必须通过 RDI、RSI、RDX 和 RCX(按照确切的顺序)。

现在我问自己两个问题。

首先,ESI 和 EDI 不应该只在字符串操作期间使用吗?如果我想将整数作为参数而不是字符串传递会发生什么?

其次,如果我需要传递 32 位参数而不是 64 位参数怎么办?例如,如果我想为系统调用write 创建一个标识符,我会这样写:

;; void write(int fd, const void *buf, size_t count);
;; Inputs   :  ESI = offset string, EDX = number of characters to write, EBX = file descriptor
;; Outputs  :  <none>
;; Clobbers :  <none>
write:
    mov ecx, esi

    mov eax, 4
    int 0x80

    ret

但是使用标准,如何将值从 64 位寄存器移动到 32 位寄存器?因为我做不到:

mov ecx, rdi ; impossible

【问题讨论】:

标签: assembly x86-64 calling-convention


【解决方案1】:

一般rdirsi can be treated as general purpose registers,即您可以将它们用于任意算术和内存操作。它们具有某些特殊含义,因为它们也用作字符串操作的索引寄存器。但是,该架构并不关心您是否在其中存储字符串指针或其他任意 64 位数字。


关于传递 32 位值,您可以简单地访问源寄存器的低 32 位部分:

mov ecx, edi

这只会将最低有效的 32 位移动到 ecx。请注意,如果您改为传递整个 64 位,这并没有真正的区别——如果被调用者只访问 32 位子寄存器ecx,结果是一样的:

mov rcx, rdi
; ...
; use ecx

关于问题中的示例代码的一个小注释:您似乎在 64 位环境中使用 32 位样式的系统调用。如果指向 buf 的指针不适合 32 位,这可能会中断。 write 系统调用的 64 位版本如下所示:

write:
    ; syscall number
    mov rax, 1

    ; all other arguments are already in the right registers
    syscall

    ret

更多信息:

【讨论】:

  • 也许值得指出 @NathanCasabieille 代码中的错误 - 指针是 64 位的,您不想将它们截断为 32 位,并且您通常不想在中使用 int 0x80 64 位代码。 What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?。或者这可能只是杂乱无章,分散了预期问题的注意力,并且已经在其他地方得到了回答。
  • @PeterCordes 这些都是有效点。我在最后添加了一个段落和一个 64 位示例 - 这不应该使答案本身混乱,并且可能对潜在的未来读者有所帮助。 :)
猜你喜欢
  • 1970-01-01
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
  • 2016-03-20
  • 1970-01-01
相关资源
最近更新 更多