函数堆栈调用 和 函数值的返回方式 以及 函数的调用约定

函数堆栈调用和函数值的返回方式以及函数的调用约定

 

函数堆栈调用:

我们先用一段简单的程序,通过反汇编的方式来分析一下函数的堆栈调用

 

反汇编代码:

 

我们现在来分析一下:

ebp:栈底指针  esp:栈顶指针  pc:下一行指令寄存器

 

从main函数开始进入:

11: int a = 10;

0010188E  mov         dword ptr [a],0Ah  //开辟空间[a] 赋值为10

12: int b = 20;

00101895  mov         dword ptr [b],14h  //开辟空间[b] 赋值为20

13: int rt = Sum(a, b);

0010189C  mov         eax,dword ptr [b]  //取空间[b]中的值,放入寄存器eax中

0010189F  push        eax                //将寄存器eax中值压栈

001018A0  mov         ecx,dword ptr [a]  //取空间[b]中的值,放入寄存器eax中

0010189F  push        eax                //将寄存器eax中值压栈

001018A3  push        ecx  

001018A4  call        Sum (01011F4h)     //call指令:1.调用Sum函数,并将下一行指令地址压栈   2.jump到被调用方函数

001018A9  add         esp,8              

001018AC  mov         dword ptr [rt],eax  

 

进入到Sum函数中:

3: int Sum(int a, int b)

4: {

00101830  push        ebp      //将ebp压栈,压入调用方的栈底指针的值

00101831  mov         ebp,esp  //移动ebp,将其移动到esp指针的地方

00101833  sub         esp,0CCh //累减器

00101839  push        ebx  

0010183A  push        esi  

0010183B  push        edi  

0010183C  lea         edi,[ebp-0CCh]  //移地址符

00101842  mov         ecx,33h  

00101847  mov         eax,0CCCCCCCCh  

0010184C  rep stos    dword ptr es:[edi]  

 

5: int tmp = a + b;

0010184E  mov         eax,dword ptr [a]  //取空间[a]中的值,放入寄存器eax中

00101851  add         eax,dword ptr [b]  //取空间[b]中的值,并将其值加入到寄存器eax中

00101854  mov         dword ptr [tmp],eax //取寄存器eax中的值,放入空间[tmp]中

6: return tmp;

00101857  mov         eax,dword ptr [tmp]  //取空间[tmp]中的值,并将其值放入到寄存器eax中

7: }

0010185A  pop         edi  

0010185B  pop         esi  

0010185C  pop         ebx  

0010185D  mov         esp,ebp  

0010185F  pop         ebp  

00101860  ret  //pc(下一行指针寄存器),ret => pop pc => pc = pop();

 

 

压栈:

调用函数:

  1. 压入形参变量的地址和值
  2. 压入函数调用返回后要执行的指令的地址

被调用函数:

  1. 压入调用函数的栈底指针,把栈底指针寄存器指向被调用函数的栈底
  2. 开辟被调用函数的栈帧大小,并初始化为0xCC CC CC CC

清栈:

调用函数:

  1. 清理形参变量的内存

被调用函数:

  1. 清理被调用函数开辟的栈帧大小
  2. 回退栈底指针到调用函数的栈底
  3. 把回退到调用函数下一行要执行的指令传入到pc寄存器

 

 

 

函数值的返回方式:

若返回值的大小为x

 

0<= x <= 4字节:则通过一个寄存器带回       4< x <=8字节:则通过两个寄存器带回

 

8< x字节:则通过临时量带回(临时量内存开辟在调用方内存块内,通过拷贝带回,临时量紧挨着实参)

 

 

 

函数的调用约定:

_cdecl    C标准调用约定       ------------

_stdcall   Windows标准调用约定         |------ >C,C++内约定,自右向左入栈

_fastcall   快速调用约定        ------------

_thiscall   类成员方法的调用约定

 

 

前三种调用约定的区别:

1:函数符号的生成

int Sum(int a, int b);                  //int __cdecl Sum(int,int)" (?Sum@@YAHHH@Z)

int _stdcall Sum(int a, int b);     //int __stdcall Sum(int,int)" (?Sum@@YGHHH@Z)

int _fastcall Sum(int a, int b);    //int __fastcall Sum(int,int)" (?Sum@@YIHHH@Z)

 

2:实参的入栈顺序

_cdecl调用约定:参数从右向左压入堆栈

_stdcall调用约定:参数从右向左压入堆栈

_fastcall调用约定:第一个和第二个参数通过寄存器ecx和edx传递,其他参数从右向左压入堆栈

 

3:形参的开辟和清理方式

_cdecl    调用方开辟,调用方清除(正是这种特性,C语言允许函数的参数个数不固定)

_stdcall   调用方开辟,被调用方清除(用寄存器保存值,若个数 >= 3个,则从第三个开始的形参开辟内存保存,被调用方清理)

_fastcall   内置类型 <= 4,前两个形参不开辟内存,通过寄存器带入,  其他 调用开辟,被调用方清理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值