0%

函数调用方式

通常函数调用方式有三种:
1)_cdecl方式
2)_stdcall方式
3) _fastcall方式

I._cdecl方式(C调用约定)

函数调用时由调用方负责将函数参数压入栈,压入顺序为从右向左;当函数结束后由调用方负责清理栈空间。
比如:void _cdecl func(int a,int b,int c)

1
2
3
4
5
push parameter c;
push parameter b;
push parameter a;
call func;
add esp,12;

II._stdcall方式(标准调用约定)

_cdecl调用方式不同的是:函数结束时由被调用函数本身负责删除栈中的函数参数,对于被调用的函数而言,函数执行这样的操作必须清楚的知道参数数量,所以通常用于接受参数数量固定不变的函数,std_call调用方式可能采用的方式如下:
ret 12; return and clear 12 bytes from stacks

优点在于每次函数调用后不需要代码从栈中清除参数,因而用于生成体积较小,速度稍快的程序;

III._fastcall方式

这种调用约定向CPU寄存器(而非程序栈)传递最多两个参数,如果指定是使用_fastcall方式,则传递给函数的前两个参数将分别位于ECX和EDX寄存器上,其余参数以类似于stdcall调用方式从右至左放入栈中。函数结束时也是由被调用方负责从栈中删除参数,并且只删除压入栈的参数,而不处理进入寄存器中的参数

补充:

在c++调用约定中,c++类中的非静态成员函数与标准函数不同,它们需要提供this指针,该指针指向用于调用函数的对象。用于调用函数的对象的地址必须由调用方提供,因此它在调用非静态成员函数的时候,必须作为参数提供,这个参数根据编译器的不同所使用的调用方式也不同;
Microsoft Visual C++ 提供thiscall调用约定,它将this传递到ECX寄存器中,并且和stdcall中一样,要求由被调用的非静态成员函数 清除栈中的参数。而GNU g++编译器则将this看作任何非静态成员函数的第一个隐含参数,其他的与cdecl调用方式相同