在设计调用约定时,x64 体系结构利用机会清除了现有 Win32 调用约定(如 __stdcall、__cdecl、__fastcall、_thiscall 等)的混乱。在 Win64 中,只有一个本机调用约定,__cdecl 之类的修饰符被编译器忽略。除此之外,减少调用约定行为还为可调试性带来了好处。
windows x64平台调用约定的主要特性如下:
- 前四个整型或指针类型参数由RCX,RDX,R8,R9依次传递,前四个浮点类型参数由XMM0,XMM1,XMM2,XMM3依次传递。
- 调用函数为前四个参数在调用栈上保留相应的空间,称作shadow space或spill slot。即使被调用方没有或小于4个参数,调用函数仍然保留那么多的栈空间,这有助于在某些特殊情况下简化调用约定。
- 除前四个参数以外的任何其他参数通过栈来传递,从右至左依次入栈。为前四个参数在调用栈上保留相应的空间。
- 由调用函数负责清理调用栈。
- 小于等于64位的整型或指针类型返回值由RAX传递。
- 浮点返回值由XMM0传递。
- 更大的返回值(比如结构体),由调用方在栈上分配空间,并有RCX持有该空间的指针并传递给被调用函数,因此整型参数使用的寄存器依次右移一格,实际只可以利用3个寄存器,其余参数入栈。函数调用结束后,RAX返回该空间的指针。
- 除RCX,RDX,R8,R9以外,RAX、R10、R11、XMM4 和 XMM5也是易变化的(volatile)寄存器。
- RBX, RBP, RDI, RSI, R12, R14, R14, and R15寄存器则必须在使用时进行保护。
- 在寄存器中,所有参数都是右对齐的。小于64位的参数并不进行高位零扩展,也就是高位是无法预测的垃圾数据。