为什么 x86-64 Linux ABI 通过寄存器中小于 16 字节的值而不是 8 来传递结构?

Jos*_*vin 4 c linux assembly x86-64 abi

在 C 级别,建议通常通过指针传递大于字大小(x86-64 上为 8 字节)的任何内容,并通过值传递任何小于字大小的内容(意味着通过寄存器)。争论的焦点应该是传递 1 个指针值比传递 N 个成员更有效。但这似乎即使对于 N=2 也应该是正确的。那么为什么 ABI 只有在超过 16 个字节时才开始使用内存呢?为什么不是8?

按值传递 16 字节结构与 24 字节传递的代码生成差异示例: https: //godbolt.org/z/5WdjEEr4E

Chr*_*odd 5

TLDR:因为这就是ABI 规范所说的要做的事情。

一般来说,最好将所有参数直接放入寄存器中,直到用完寄存器为止,此时并不清楚哪些参数最好放入寄存器中。这很大程度上取决于被调用者如何使用这些参数,但是调用约定需要仅根据调用者拥有的信息来确定,而调用者可能不包括这些信息。

由于 Linux/SYSV ABI 允许 6 个参数寄存器,因此有足够的空间可以容纳两个字参数以及一个字参数,但如果只有 2 个 3 字参数,则会用完所有寄存器。因此,将 2 字参数放入寄存器是一种折衷方案,在一般情况下似乎效果很好。

由于 MS ABI 仅使用 4 个参数寄存器,因此权衡略有不同。

  • Windows x64 还旨在使可变参数函数尽可能简单/高效(通常以普通函数的效率为代价),因此每个 arg 恰好占用一个 64 位插槽。这是他们传递大参数指针而不是像 AMD64 SysV 那样传递堆栈上的整个结构值的原因之一。 (4认同)