【发布时间】:2016-10-24 10:29:42
【问题描述】:
va_arg \ va_start \ va_list \ va_end 宏在 x64 中如何工作?
i386 中的调用约定在堆栈上传递参数,因此宏只是增加一些指向堆栈基址的指针并转发它。 但是,在 x64 中,所有参数都由寄存器传递......那么那里会发生什么?被调用函数如何知道哪些寄存器用于传递参数以确保它不会破坏它们?
【问题讨论】:
-
一些(很多?)编译器可能在 x64 模式下在寄存器中传递参数,但这不是 x86 与 x64 的固有差异,这是他们的选择。此外,它们不能总是在寄存器中传递 all 参数(一个有 100 个参数的函数?)。
va_list可以保存在寄存器中传递了多少参数以及它必须传递到哪个参数的详细信息,但我的 猜测 是可变参数参数在所有情况下都简单地在堆栈上传递。跨度> -
This blog post 描述它
-
@TripeHound 这不取决于编译器。为什么人们相信这个神话并传播它?虽然编译器可以为所欲为,但这样的编译器毫无价值。编译器以具有非常明确定义的 ABI 的架构为目标。并且当前存在的 x64 ABI 都指定了用于传递函数参数的寄存器。即使对于可变参数函数(这些函数与普通函数之间没有区别)。
-
@Art 对不起,我很马虎。在我看来,我的意思是“编译器和它所针对的 ABI”。做出自己选择的编译器可能并非毫无价值的一种情况是嵌入式系统,它可能不遵循任何标准 ABI。从this MSDN page 看来,微软在寄存器中传递了前 4 个参数(但如果需要,调用者必须在堆栈上留出空间以充当卷影副本),其余的都在堆栈上。对于非原型或可变参数函数,前四个中的 FP 值作为 FP 和整数传递。
标签: c x86-64 calling-convention variadic-macros