【问题标题】:Variadic arguments and x64可变参数和 x64
【发布时间】: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


【解决方案1】:

这是由架构的 ABI 定义的。在 amd64 的 SysV ABI(几乎除了 Windows 之外的所有东西)上,ABI document 说(第 56 页及以后):

采用变量参数列表并已知调用宏 va_start 的函数的序言预期将参数寄存器保存到寄存器保存区域。

那么va_list 是一个结构体,它带有一个指向寄存器保存区域的指针,以及堆栈中可以传递一些附加参数的位置(并非所有函数参数都适合寄存器)。

【讨论】:

  • 这意味着这需要编译器支持并且每个可变参数函数都应该将所有寄存器保存在堆栈上?
  • @DrPrItay:ABI 指定哪些寄存器可以用于什么。 16 个整数寄存器中只有 6 个用于参数传递(在 SysV 调用约定中),而其他寄存器总是允许被函数调用破坏。
  • 一些解释可以找到in this blog
猜你喜欢
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-07
  • 1970-01-01
相关资源
最近更新 更多