调用约定
x86 calling conventions
用如下示例程序:
int fun(int a,int b)
{
return 0;
}
int main()
{
fun('\1','\2');
return 0;
}
C语言调用约定 (VC默认用的这个)
在声明函数时用__cdecl修饰,例如:int __cdecl fun(int a,int b)
fun('\1','\2');展成汇编代码如下:
push 2 //从右至左,将参数推进堆栈
push 1
call @ILT+0(_fun) (00401005)//符号的形式为 下划线+函数名,当函数调用完函数以 ret 返回
add esp,8 //此时的堆栈和调用前的堆栈不一致,需要“调用者”恢复堆栈,用add指令将堆栈恢复平衡。
注:c语言调用会在目标(Object)文件中产生一个符号代表这个函数,此符号的形式为 下划线+函数名,且函数以ret形式返回。
注:CPU执行ret指令时,进行下面两步操作:(IP)=((SS)*16+(SP));(SP)=(SP)+2;
标准调用约定
用__stdcall修饰,例如:int __stdcall fun(int a,int b)
fun('\1','\2');展成汇编代码如下:
00401068 push 2//从右至左
0040106A push 1
0040106C call @ILT+0(_fun@8) (00401005) //符号的形式为 下划线+函数名+X,当函数调用完函数以 ret X返回(这里X为8)
//“调用者”不负责恢复堆栈。
注:“别调用者”fun函数负责恢复堆栈,而“调用者”不需要恢复堆栈。这个是C语言调用和标准调用最重要的区别之一。
注:符号的形式为 下划线+函数名+X。其中,X代表清理堆栈是需要的数字,函数以ret X形式返回。
注:CPU执行ret n 指令时 等效于(IP)=((SS)*16+(SP));(SP)=(SP)+2;(SP)=(SP)+n;
快速调用约定
用__fastcall修饰,例如:int __fastcall fun(int a,int b)
fun('\1','\2');展成汇编代码如下:
00401078 mov dl,2//从右至左,注意这里用的是mov,不是push,所以后面不用恢复堆栈。
0040107A mov cl,1
0040107C call @ILT+0(@fun@8) (00401005)//符号形式为 函数名+X 当函数调用完函数以ret返回。
C++类成员函数的调用约定thiscall
c++默认,不用修饰
fun('\1','\2');展成汇编代码如下:
00401068 push 2//从右至左
0040106A push 1
0040106C call @ILT+5(fun) (0040100a)//符号的形式为 函数名,当函数调用完函数以 ret 返回
00401071 add esp,8
附上MSDN上的解释:
以下代码为例:
void calltype MyFunc( char c, short s, int i, double f );
...
void MyFunc( char c, short s, int i, double f )
{
...
}
...
MyFunc ('x', 12, 8192, 2.7183);
例子代码的结果为:
__cdecl
The C decorated function name is "_MyFunc."
__stdcall and thiscall
The C decorated name (__stdcall) is "_MyFunc@20." The C++ decorated name is proprietary.
__fastcall
The C decorated name (__fastcall) is "@MyFunc@20." The C++ decorated name is proprietary.