为什么Windows64使用与x86-64上所有其他操作系统不同的调用约定?
AMD有一个ABI规范,描述在x86-64上使用的调用约定。除了有自己的x86-64调用约定的Windows之外,所有操作系统都遵循它。为什么? 有人知道造成这种差异的技术、历史或政治原因吗,还是这纯粹是一个尼希德综合征的问题 我知道不同的操作系统可能对更高级别的东西有不同的需求,但这并不能解释为什么例如Windows上的寄存器参数传递顺序是为什么Windows64使用与x86-64上所有其他操作系统不同的调用约定?,windows,x86-64,calling-convention,Windows,X86 64,Calling Convention,AMD有一个ABI规范,描述在x86-64上使用的调用约定。除了有自己的x86-64调用约定的Windows之外,所有操作系统都遵循它。为什么? 有人知道造成这种差异的技术、历史或政治原因吗,还是这纯粹是一个尼希德综合征的问题 我知道不同的操作系统可能对更高级别的东西有不同的需求,但这并不能解释为什么例如Windows上的寄存器参数传递顺序是rcx-rdx-r8-r9-rest-on-stack,而其他所有操作系统都使用rdi-rsi-rdx-rcx-r8-r9-rest-on-stack 另外
rcx-rdx-r8-r9-rest-on-stack
,而其他所有操作系统都使用rdi-rsi-rdx-rcx-r8-r9-rest-on-stack
另外,我知道这些通话约定通常有什么不同,如果需要,我知道在哪里可以找到详细信息。我想知道的是为什么
编辑:有关如何操作,请参见此处的和链接 Win32对ESI和EDI有自己的用途,并且要求不修改它们(或者至少在调用API之前恢复它们)。我想象64位代码对RSI和RDI也有同样的作用,这就解释了为什么它们不用于传递函数参数 但是,我无法告诉您为什么要切换RCX和RDX。在x64上选择四个参数寄存器-UN*X/Win64通用 关于x86,需要记住的一点是,“regnumber”编码的寄存器名并不明显;就指令编码而言(MOD R/M字节,请参阅),寄存器号0…7按顺序为:AX、
、CX
、、DX
、、BX
、、SP
、、BP
、、SI
、、DI
因此,选择A/C/D(regs 0..2)作为返回值和前两个参数(这是“经典的”32位\uu fastcall
约定)是一个合乎逻辑的选择。就64位而言,订购了“更高”的regs,微软和UN*X/Linux都选择了R8
/R9
记住这一点,如果您选择四个寄存器作为参数,那么微软选择的RAX
(返回值)和RCX
,RDX
,R8
,R9
(arg[0..3])是可以理解的选择
我不知道为什么AMD64 UN*X ABI在RCX
之前选择了RDX
在x64上选择六个参数寄存器-UN*X特定
RISC架构上的UN*X传统上在寄存器中传递参数——特别是对于前六个参数(至少在PPC、SPARC、MIPS上是这样)。这可能是AMD64(UN*X)ABI设计人员选择在该体系结构上使用六个寄存器的主要原因之一
因此,如果希望六个寄存器传入参数,并且为其中四个寄存器选择RCX
、RDX
、R8
和R9
,那么您应该选择另外两个
“更高”的regs需要一个额外的指令前缀字节来选择它们,因此具有更大的指令大小占用空间,因此如果有选项,您不想选择其中任何一个。在经典寄存器中,由于RBP
和RSP
的隐含含义,这些寄存器不可用,RBX
传统上在UN*X(全局偏移表)上有特殊用途,AMD64 ABI设计者似乎不希望不必要地与之不兼容。因此,唯一的选择是RSI/
RDI
所以,如果你必须把RSI/RDI
作为参数寄存器,它们应该是哪些参数
使它们成为arg[0]
和arg[1]
有一些好处。见赵的评论。?SI
和?DI
是字符串指令源/目标操作数,如cHao所述,它们用作参数寄存器意味着使用AMD64 UN*X调用约定,例如,最简单的strcpy()
函数只包含两条CPU指令repz movsb;ret
,因为调用者已将源/目标地址放入正确的寄存器中。特别是在低级编译器生成的“胶粘”代码中(例如,在构建中,一些C++堆分配器零填充对象,或者内核零填充堆页在RSI
/RDI
寄存器中“预先”了两个附加参数,而在RCX
、RDX
、R8
和R9
寄存器中自然选择了四个参数
除此之外。。。
UN*X和Windows x64 ABI之间的区别不仅仅是参数到特定寄存器的映射。有关Win64的概述,请选中:
Win64和AMD64 UN*X在stackspace的使用方式上也有显著差异;例如,在Win64上,调用方必须为函数参数分配堆栈空间,即使参数0…3在寄存器中传递。另一方面,在UN*X上,叶函数(即不调用其他函数的函数)如果需要的堆栈空间不超过128字节,则根本不需要分配堆栈空间(是的,您拥有并可以使用一定数量的堆栈,而无需分配它……除非您是内核代码,这是一个漂亮的bug源)。所有这些都是特定的优化选择,这些选择的大部分原理都在原始海报的维基百科所指向的完整ABI参考文献中进行了解释。IDK为什么Windows会这样做。请参阅此答案的结尾部分以了解猜测。我很好奇这个系统是如何运作的