调用约定 小结

来源:互联网 发布:医疗器械软件测试报告 编辑:程序博客网 时间:2024/05/19 15:25

1.C调用约定 _cdecl

从右到左将函数参数入栈,调用方负责平衡栈

void demo_cdecl(int w,int x,int y,int z);
push 4push 3push 2push 1call demo_cdecladd esp,16
;demo_cdecl(1,2,3,4);gnu(gcc g++采用这种技巧将函数参数放到栈上)mov [esp+12],4mov [esp+8],3mov [esp+4],2mov [esp],1call demo_cdecl

2.标准调用约定 _stdcall

void _stdcall demo_stdcall(int w,int x,int y);

从右到左的顺序将参数入栈,函数结束执行时,又被调用的函数负责删除栈中的函数参数,平衡栈。
对被调用函数而言,必须清楚知道栈上有多少个参数,只有在函数接受的参数数量固定才可行。
所以对于printf这种接受可变数量的参数的函数不能使用stdcall

//demo_stdcall中有三个参数 占用了 3*sizeof(int)=12 (在32位体系结构的cpu上) x86编译器使用ret指令//从栈顶提取返回地址并平衡栈指针,清除参数.ret 12

3.x86 fastcall

fastcall属于stdcall的一个变体,向cpu寄存器最多传递两个参数。
msvc++ 和 gnu的gcc/g++能够识别fastcall的修饰符,如果指定fastcall,前两个参数将分别位于ECX,EDX寄存器中,剩余的参数类似于stdcall约定方式入栈,同样 fastcall函数(被调用方)负责平衡栈

void fastcall demo_fastcall(int w,int x,int y,int z);
;demo_fastcall(1,2,3,4)push 4push 3mov edx,2mov ecx,1call demo_fastcall

4.C++调用约定

ms v c++提供this call调用约定,将this传递到ECX寄存器中,并且和stdcall中一样,它要求非静态成员函数清除栈中的参数。
gnu g++编译器将this看成是任何非静态成员函数中的第一个隐含参数,而在其他方便与cdecl约定相同,因此对于使用g++编译的代码来说,在调用非静态成员函数之前,this被放置到栈顶,切调用方负责在啊含糊返回时删除栈中的参数(至少有个一)。

5.其他调用约定

调用约定是特定于语言、编译器、cpu的。
对于 优化代码,定制汇编语言和系统调用等情况需要特别注意。

0 0