假设我们有一个具有以下签名的 C(或 C++)函数:
void foo(int64_t a, double b, int64_t c, double d);
在 Linux、Mac 或任何使用 System V ABI (x86_64) 的操作系统上编译时,a
和c
在 rdi
中获得通过和rsi
寄存器,和b
和d
传入xmm0
和xmm1
。好吧,这没什么问题。但后来我在 Windows (x86_64) 中做了同样的事情,看起来它跳过了一些寄存器。 a
和c
传入rcx
和r8
( rdx
已跳过)和 b
和d
传入xmm1
和xmm3
(xmm0
和 xmm2
已跳过)。为什么 Win64 这样做而不是像 System V 那样“压缩”参数?对于 System V,我想象能够传递 4 个 qword 和 4 个 double ,而不需要传递堆栈上的任何内容,而 Win64,正如我猜测的那样,会传递堆栈上第四个参数之后的任何内容。/p>
我知道 Win64 与 SysV 中参数传递的寄存器顺序存在差异,但顺序不应该相关。我只是好奇为什么 Win64 会跳过寄存器,特别是当它只有 4 个用于非堆栈参数传递时。
最佳答案
微软的文档
https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160
声明它们在寄存器中最多传递 4 个参数。如果某个参数不适合特定寄存器,则将跳过该寄存器。
“浮点和 double 参数在 XMM0 - XMM3(最多 4 个)中传递,整数槽(RCX、RDX、R8 和 R9)通常用于该基数槽被忽略(参见示例),反之亦然。”
链接页面上的示例 3 正是您的示例,并解释了您所看到的效果:
func3(int a, double b, int c, float d);
// a in RCX, b in XMM1, c in R8, d in XMM3
因此,他们使用最多 4 个参数寄存器,第一个参数在 RCX 或 XMM0 中,第二个参数在 RDX 或 XMM1 中,等等。
那么为什么要这样做呢?也许将 8 个寄存器参数传递给函数的想法似乎不是一个重要的用例。
关于c++ - Win64 与 System V ABI (x86_64) : Win64 Skipping registers?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45699107/