调用约定指的是函数在被调用的时候,会按照不同德规则,翻译成不同的汇编代码。为了解释这个概念,首先了解一下调用堆栈的概念。当一个函数被调用时,首先会将返回地址压入堆栈,紧接着会将函数的参数依次压入堆栈。当函数推出时会以相反的顺序依次退出堆栈,因此,函数在被调用前和调用后的堆栈保持平衡。
不同的调用约定,会指明不同的参数入栈顺序,还会指明不同的清理堆栈的方法。用C语言或者C++语言编译器编译程序的时候,会按照四种不同的调用约定去编译函数。其分别是C语言调用约定,函数由__cdecl修饰。标准调用约定,函数由__stdcall修饰,快速调用约定,函数由__fastcall修饰,c++类成员函数的调用约定,函数由thiscall修饰,不同的调用约定编译后,会产生不同的汇编代码。
1.c语言调用约定
c语言调用约定,要求在申明函数时用_cdecl对函数进行修饰,例如:
void __cdecl Foo(int a ,int b);
c语言调用会在目标(object)文件中产生一个符号来代表这个函数,此符号的形式为下划线+函数名,且函数体以ret形式放回,如:
Foo(0x12345678,0x11223344);
即从右至左,将参数推进堆栈,执行结束后,以ret返回。c语言调用约定需要调用者恢复堆栈.
2.标准调用约定
从右至左,将参数推进堆栈,当函数调用完,函数以ret8返回函数,Foo函数负责恢复堆栈,而调用者不负责恢复堆栈,这是c语言调用和标准调用最重要的区别之一。
用ddk编译程序时,默认的是使用标准调用约定。