使用寄存器而不是堆栈从 x64 程序集调用 C 函数
Posted
技术标签:
【中文标题】使用寄存器而不是堆栈从 x64 程序集调用 C 函数【英文标题】:Calling C function from x64 assembly with registers instead of stack 【发布时间】:2015-04-20 12:06:59 【问题描述】:This answer 让我很困惑。
根据standard C calling conventions,调用C 函数的标准方法是将push
参数传递给堆栈和call
子例程。这与syscalls 明显不同,在syscalls 中,您使用适当的参数设置不同的寄存器,然后syscall
。
但是,上面提到的答案给出了这个 GAS 代码:
.global main
.section .data
hello: .asciz "Hello\n"
.section .text
main:
movq $hello, %rdi
movq $0, %rax
call printf
movq $0, %rax
ret
适用于gcc hello.s -o hello
。调用printf
的部分是:
movq $hello, %rdi
movq $0, %rax
call printf
它使用rdi
寄存器而不是堆栈将参数传递给printf
。将上述更改为
push $hello
call printf
导致分段错误。
由于printf
是一个C 函数,与sys_write
不同,我认为应该将参数传递给堆栈,而不是寄存器。我在这里有什么误解?其他标准 C 函数呢,比如malloc
?
(任何参考将不胜感激。)
【问题讨论】:
“约定”不是“标准”。在 64 位世界中情况有所不同。看看this Wikipedia article。 和你一样的问题:***.com/questions/17193786/… 【参考方案1】:将参数传递给可变参数函数更加复杂。请参阅x86-64 ELF ABI,第 3.5.7 节。否则,x86-64 使用寄存器传递其前 6 个参数:%rdi, %rsi, %rdx, %rcx, %r8, %r9
(不包括浮点/向量参数)。
根据规范,%rax = 0
表示变量参数列表没有 (0) 浮点参数传入向量寄存器。你的方法是错误的,因为第一个参数(例如,以 nul 结尾的字符串:"Hello\n"
)必须在%rdi
中传递,并且在调用函数时%rax
必须为零。
【讨论】:
这正是我一直在寻找的。非常感谢。以上是关于使用寄存器而不是堆栈从 x64 程序集调用 C 函数的主要内容,如果未能解决你的问题,请参考以下文章
.NET 4.0 NGEN x64 程序集上的符号解析不起作用
对于 ARM Aarch64 的 NEON 编码,如何将寄存器推送到堆栈?似乎 STMFD 不是 Aarch64 指令集的一部分?