调用约定
不同的调用约定需要定义参数传递的方式,堆栈平衡的方式以及返回值保存在何处。不同cpu架构使用的调用约定也不相同。
x86调用约定
_stdcall
_stdcall调用约定是windows API使用的调用约定,其规定了函数在调用时参数从右向左入栈,被调用者进行堆栈平衡,返回值保存在eax中。
_cdecl
如果单单只有_stdcall的话会有一个问题,对于可变参数的函数而言,因为函数本身不知道会有几个参数传递,所以自身无法进行堆栈的平衡。这就产生了_cdecl调用约定,此调用约定会与_stdcall唯一的区别就是其规定由函数调用者平衡堆栈。
_fastcall
_fastcall调用约定是一种快速调用约定,其比上述两种调用约定快速的原因就是其使用寄存器传参,相对于使用内存进行传参要块。其规定函数的前两个参数使用ecx和edx,而其余参数从右向左依次入栈,由被调用者进行堆栈平衡。返回值保存在eax中。
_thiscall
_thiscall调用约定是唯一一种不能显示指定的调用约定,c++语言默认使用这种调用约定。其最大的特点就是使用ecx寄存器传递this指针。
x64调用约定
x64调用约定只有一种调用约定,这种调用有点类似与x86的fastcall,但又不完全相同。
其使用rcx,rdx,r8,r9来传递函数的前四个参数,然后其余的参数通过堆栈传递,堆栈由被调用者平衡,结果保存在rax中。这里面有一个重点就是x64下参数传递超过4个后通过堆栈传递,但是并不进行压栈操作,而是直接将参数mov到对应的堆栈中。
这样因为参数传递没有涉及堆栈操作,所以x64上函数调用不涉及到堆栈平衡的问题。这也就解决了x86上含有可变参数的函数调用过程中的堆栈平衡问题,x64下参数传递无需进行堆栈平衡。
如果在x64中显式指定函数的调用约定,编译器会直接忽略。