使用寄存器而不是堆栈从 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
必须为零。
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
必须为零。