一、正文:
1、什么是调用约定
在一个函数调用另一个函数的时候,有时需要向其传递参数,并且拿到被调用函数运行后的返回值,调用约定就是为了规范这两个过程的实际物理操作,另外还可以在高级语言转为汇编语言的时候指定汇编代码中函数名的修饰方式
即调用约定的作用有:
- 规定传参的方式
- 规定返回值返回的方式
- 规定汇编代码中函数名的修饰方式
更具体一点,传参和返回值返回的“方式”可以被进一步具体为“参数和返回值放在哪里?(堆栈还是寄存器)”以及“调用完成后由谁来清理这些临时数据?(调用函数还是被调用函数)”
2、各种调用约定的具体规则
下面只以 微软visual c/c++ 环境下的部分调用约定举例说明
1)C语言中:
__cdecl
__cdecl调用约定的主要特征是:
1.参数从右向左传递,并放置在堆栈上。
2.堆栈清理由调用方执行。
3.函数名用下划线“_”作为前缀来修饰。
__stdcall(相当于WINAPI)
__stdcall调用约定的主要特征是:
1.参数从右向左传递,并放置在堆栈上。
1.堆栈清理由被调用的函数执行。
1.函数名由一个下划线字符和一个’@'字符以及所需堆栈空间的字节数来修饰。
__fastcall
__fastcall调用约定的主要特征是:
1.前两个需要32位或更少的函数参数被放置在寄存器ECX和EDX中。其余的被从右向左推入堆栈。
2.参数由被调用的函数从堆栈中弹出。
3.函数名由以下方式修饰:在前面加上一个’@‘字符,并附加一个’@'和参数所需的字节数(十进制)。
2)C++中:
Thiscall
Thiscall调用约定的主要特征是:
1.参数从右向左传递,并放置在堆栈上。
2.它被放置在ECX中。堆栈清理由被调用的函数执行。
3、总结
调用约定之间的主要区别:
1.__cdecl是C和c++程序的默认调用约定。这种调用约定的优点是,它允许使用具有可变数量参数的函数。缺点是它创建了更大的可执行文件。
2.__stdcall用于调用Win32 API函数。它不允许函数有可变数量的参数。
3.__fastcall尝试将参数放入寄存器中,而不是堆栈中,从而使函数调用更快。
4.Thiscall调用约定是不使用变量参数的c++成员函数使用的默认调用约定。
二、注:
本文为笔者读完Nemanja Trifunovic所著博客《Calling Conventions Demystified》后的总结,原博客链接为:《Calling Conventions Demystified》,更多示例代码和本文未提及的细节请参考原文。