这几天公司项目不忙,base公司某高手的ppt,小小研究了一下c++中的calling convention的相关内容。
1.什么是calling convention?
中文译为调用约定。再细说就是在函数调用过程中,主调函数与被调函数之间的约定。如下func1就是主调函数,func2就是被调函数
void func1()
{
func2(params);
}
2.为什么要有调用约定?
为了进行堆栈平衡。何谓堆栈平衡,函数在调用过程中,要对函数参数进行压栈操作,因此在函数调用之后,双方需要约定由谁来进行这些压栈操作的恢复。
3.都有哪些调用约定?
_cdecl,_stdcall,thiscall,Fastcall etc,其中比较重要的是前两种。其中_cdecl约定为调用方进行堆栈平衡,_stdcall约定为被调方进行堆栈平衡。
介绍完了一些基本的概念,下面用一个例子来进一步说明问题:
C++代码非常简单:
void _stdcall test_convention(int a) //这里首先将函数声明为_stdcall,约定被调方,也就是被调函数进行堆栈平衡
{
printf("%d,%d/n",a);
}
void main()
{
test_convention(1); //test_convention就是被调函数
system("pause");
}
程序生成的反汇编代码:
test_convention(1);
//将变量1压栈
0041145E push 1
//函数调用
00411460 call 004111A4
F11跟进call之后的代码,反汇编如下:
void _stdcall test_convention(int a)
{
//***********此处省略若干行*********
//这句是关键,相当于ESP + 8(ret本身相当于+4),被调方进行堆栈平衡
0041141C ret 4
然后我们将函数的调用约定修改为_cdecl,约定为调用方进行堆栈平衡
void _cdecl test_convention(int a)
test_convention(1);
0041144E push 1
00411450 call 0041119F
同样F11跟进去之后
//**********此处省略若干行**********
//只有一句ret
ret
//但在主调函数生成的汇编代码中,呵呵确实如此,调用方进行堆栈平衡
00411455 add esp,4
至此为止,堆栈平衡的大概原理讲述完毕,如果想进一步深入的了解函数调用的汇编语言过程,不妨随便写个函数反汇编一下看看。
对了,如果你也像我一样是个菜鸟,不妨google一下ESP和EBP的意思,相信会对你有所帮助。
第一篇博客,值得纪念一下:)
2010-1-06 global_var