为什么参数存储在寄存器中而不是 x86-64 汇编中的堆栈中?

Why parameters stored in registers and not on the stack in x86-64 Assembly?

在 x86-32 汇编中,参数存储在堆栈中,但在 x86-64 中,参数存储在寄存器中。这是什么原因?

访问 CPU 寄存器比访问 RAM 快(很多)。

由于 64 位 CPU 有更多的通用寄存器(与 64 位无关,只是因为它们是 newer/bigger),使用它们是有意义的。

Store/reload 往返需要指令并花费大约 6 个周期的存储转发延迟,因此现代调用约定使用更高效的设计。这在某些情况下也节省了指令,因为调用者可以只在寄存器中生成 arg 而不是推送它。 (并且不必在 return 之后弹出堆栈)。

由于x86-64是一种新模式,对向后兼容没有任何要求,所以可以设计一个没有遗留包袱的全新ABI。有关 x86-64 SysV 调用约定的设计方式以及它比 Windows x86-64 调用约定更高效的原因,请参阅 this answer。 (红色区域,更多的参数传递寄存器。)它比 windows 约定更复杂,尤其是对于可变参数函数。


在 32 位代码中,在寄存器中传递前几个参数也更有效,但引入新的调用约定会破坏与库的向后兼容。

即便如此,MS 使用 __fastcall / __vectorcall 做到了这一点,即使在 32 位模式下,它也使用两个调用破坏的寄存器(ecx 和 edx)进行 arg 传递。这些调用约定的 64 位版本使用更多的 arg 传递寄存器,因为 x86-64 有更多的 GP 寄存器。

Unix/Linux 没有尝试引入 32 位的新调用约定,基本上只是放弃了 32 位,因为过时的遗留代码一直很慢。 (尽管 32 位 SysV ABI 扩展了用于在向量 regs 中传递/returning 16B SSE 和 32B AVX 向量的规则,而不是在堆栈上)。

请参阅 标记 wiki 以获取调用约定文档的链接,以及性能链接以获取有关存储转发延迟的更多详细信息。