使用寄存器而不是堆栈从 x64 程序集调用 C 函数

Calling C function from x64 assembly with registers instead of stack

This answer我很困惑。

根据standard C calling conventions, the standard way to call C functions is to push arguments to the stack and to call the subroutine. That is clearly different from syscalls,你用适当的参数设置不同的寄存器,然后syscall

然而,上面提到的答案给出了这个 GAS 代码:

        .global main
        .section .data
hello:  .asciz "Hello\n"
        .section .text
main:
        movq $hello, %rdi
        movq [=10=], %rax
        call printf
        movq [=10=], %rax
        ret

gcc hello.s -o hello 配合使用。调用printf的部分是:

        movq $hello, %rdi
        movq [=11=], %rax
        call printf

它使用 rdi 寄存器,而不是堆栈,将参数传递给 printf。将上面的更改为

        push $hello
        call printf

导致分段错误。

因为 printf 是一个 C 函数,不像 sys_write,我认为参数应该被传递到堆栈,而不是寄存器。我在这里误解了什么?其他标准 C 函数呢,例如 malloc?

(任何参考将不胜感激。)

向可变参数函数传递参数更加复杂。请参阅 x86-64 ELF ABI,第 3.5.7 节。否则,x86-64 使用寄存器传递其前 6 个参数:%rdi, %rsi, %rdx, %rcx, %r8, %r9(不包括浮点数/矢量参数)。

根据规范,%rax = 0 表示可变参数列表没有 (0) 个在向量寄存器中传递的浮点参数。您的方法是错误的,因为必须在 %rdi 中传递第一个参数(例如,以 nul 结尾的字符串:"Hello\n"),并且在调用函数时 %rax 必须为零。