欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++_调用约束

程序员文章站 2022-07-09 20:49:01
1、要求 声明定义处调用约定必须相同 int __stdcall add(int a, int b); int __stdcall add(int a, int b) { return a + b; } 2、函数调用过程 假设:A为调用者,B为被调者;A{B}; 函数调用过程可以这么描述: (1)先 ......

1、要求

  声明定义处调用约定必须相同

  int __stdcall add(int a, int b);

  int __stdcall add(int a, int b)

  {

     return a + b;

  }

2、函数调用过程

  假设:a为调用者,b为被调者;a{b};

  函数调用过程可以这么描述:

    (1)先将调用者(a)的堆栈的基址(ebp)入栈,以保存之前任务的信息。

    (2)然后将调用者(a)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者b的栈底)。

    (3)然后在这个基址(被调用者b的栈底)上开辟(一般用sub指令)相应的空间用作被调用者b的栈空间。

    (4)函数b返回后,从当前栈帧的ebp即恢复为调用者a的栈顶(esp),使栈顶恢复函数b被调用前的位置;然后调用者a再从恢复后的栈顶可弹出之前的ebp值(可以这么做是因为这个值在函数调用前一步被压入堆栈)。这样,ebpesp就都恢复了调用函数b前的位置,也就是栈恢复函数b调用前的状态。

这个过程在at&t汇编中通过两条指令完成,即:

C++_调用约束

3、__cdecl

 

  __cdecl c declaration 的缩写,表示 c c++ 默认的函数调用约定。是c/c++mfcx的默认调用约定。

 

  按从右至左的顺序压参数入栈。a(b,c,d);先进d->c->b

 

  由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的,返回值在eax中。因此对于像printf这样可变参数的函数必须用这种约定。

  编译器在编译的时候对这种调用规则的函数生成修饰名的时候,在输出函数名前加上一个下划线前缀,格式为_function。如函数int add(int a, int b)的修饰名是_add

 

4__stdcall

 

  __stdcallstandard call的缩写,是c++的标准调用方式,当然这是微软定义的标准,__stdcall通常用于win32 api(可查看winapi的定义)

 

  按从右至左的顺序压参数入栈。

 

  由被调用者把参数弹出栈。切记:函数自己在退出时清空堆栈,返回值在eax中。

  __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_function@number。如函数int sub(int a, int b)的修饰名是_sub@8

 

5__fastcall

 

  __fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的。

 

  实际上__fastcallecxedx传送前两个dword或更小的参数,剩下的参数仍自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈。

  __fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@function@number,double multi(double a, double b)的修饰名是@multi@16

  __fastcall__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第1个参数进ecx,第2个进edx,其他参数是从右向左的入栈,返回仍然通过eax

 

6、__pascal

 

  这种规则左向右传递参数,通过eax返回,堆栈由被调用者清除

 

7、__thiscall

 

  __thiscallc++类成员函数缺省的调用约定,但它没有显示的声明形式。因为在c++类中,成员函数调用还有一个this指针参数,因此必须特殊处理,thiscall调用约定的特点:

 

  参数入栈:参数从右向左入栈

 

  his指针入栈:如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入栈。

  栈恢复:对参数个数不定的,调用者清理栈,否则函数自己清理栈。

 8、总结

调用规则

入栈顺序

清栈责任

__cdecl

从右到左

调用者

__stdcall

从右到左

被调用者

__fastcall

从右到左(先 edx、ecx,再到堆栈)

被调用者

__pascal

从左到右

被调用者

 

 C++_调用约束