函数的调用过程(栈帧的创建和销毁)

  为了更好地认识函数的调用过程,我们可以用反汇编代码去理解学习。

一、基本概念

1.栈帧(过程活动记录):是编译器用来实现函数调用的一种数据结构,每个栈帧对应一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。

2.栈(stack):又名堆栈,是一种运算受限的线性表,只允许在表的一端输入输出,这一端叫栈顶,相对的另一端是栈底,遵循后进先出,栈底是高地址,栈顶是低地址,栈由内存高地址向低地址生长。

3.push: 压栈    pop:出栈

4.寄存器: 位于CPU内部,存放运行程序中的数据和指令。

ebp (栈帧的栈底指针)     esp(栈帧的栈顶指针)

二、调用add函数的代码

#include <stdio.h>
int add(int a, int b)
{
	int ret = 0;
	ret = a + b;
	return ret;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret = add(a, b);
	return 0;
}

三、截取的部分反汇编代码,进行逐语句分析

int main()
{
00B81410  push        ebp             //在此之前,main函数在mainCRTstartup中调用,先为mainCRTsturtup开辟栈帧,有栈底,有栈顶。现在开始压栈。
00B81411  mov         ebp,esp       //让ebp指向esp的位置。
00B81413  sub         esp,0E4h     //esp指向[esp-oE4h]的位置,sub为减
00B81419  push        ebx             //分别将ebx、esi、edi压栈
00B8141A  push        esi  
00B8141B  push        edi  

00B8141C  lea         edi,[ebp-0E4h]           //加载有效地址,让edi存放[ebp-0E4h]的位置,1C至2C表示对空间进行初始化,从edi所指向的位置开始向高地址进行拷贝,初始内容为0CCCCCCCCh,拷贝39次
00B81422  mov         ecx,39h
00B81427  mov         eax,0CCCCCCCCh  
00B8142C  rep stos    dword ptr es:[edi]  

int a = 10;
00B8142E  mov         dword ptr [a],0Ah      //将10赋值于给a变量分配的空间
int b = 20;
00B81435  mov         dword ptr [b],14h       //将20赋值于给b变量分配的空间
int ret=add(a, b);
00B8143C  mov         eax,dword ptr [b]       //进行传参,让寄存器eax存放b的值
00B8143F  push        eax                          //将eax压栈
00B81440  mov         ecx,dword ptr [a]       //进行传参,让寄存器ecx存放a的值
00B81443  push        ecx                          //将ecx压栈
00B81444  call        _add (0B810E6h)       //call指令下一条地址,为add函数的调用及返回做准备

——————————————————————————————————————

00B810DC  jmp         00B83BBE  
__ValidateImageBase:
00B810E1  jmp         00B82910  
_add:
00B810E6  jmp         00B813C0                //即进入add函数
_GetProcessHeap@0:
00B810EB  jmp         00B83C2A  
__RTC_SetErrorFuncW:

——————————————————————————————————————
int add(int a, int b)
     4: {
00B813C0  push        ebp                //ebp压栈,是main函数的ebp
00B813C1  mov         ebp,esp          //让ebp指向esp的位置。
00B813C3  sub         esp,0CCh       //esp指向[esp-0CCh]的位置,sub为减
00B813C9  push        ebx                //分别将ebx、esi、edi压栈
00B813CA  push        esi  
00B813CB  push        edi  

00DC13CC  lea         edi,[ebp-0CCh]        //加载有效地址,让edi存放[ebp-0CCh]的位置,CC至DC表示对空间进行初始化,从edi所指向的位置开始向高地址进行拷贝,初始内容为0CCCCCCCCh,拷贝33次
00DC13D2  mov         ecx,33h  
00DC13D7  mov         eax,0CCCCCCCCh  
00DC13DC  rep stos    dword ptr es:[edi]  
     5: int ret = 0;
00DC13DE  mov         dword ptr [ebp-8],0              //将0放入[ebp-8]处
     6: ret = a + b;
00DC13E5  mov         eax,dword ptr [ebp+8]          //将[ebp+8]处的值10放入eax
00DC13E8  add         eax,dword ptr [ebp+0Ch]      //将[ebp+0Ch]处的值20放入eax并相加,得eax中的值为30.
00DC13EB  mov         dword ptr [ebp-8],eax          //将eax的内容拷贝在[ebp-8]中,即ret变量
     7: return ret;
00DC13EE  mov         eax,dword ptr [ebp-8]          //将ret的值存入eax中
     8: }
00DC13F1  pop         edi                                    //edi、esi、ebx、出栈,栈帧逐渐开始销毁
00DC13F2  pop         esi  
00DC13F3  pop         ebx  
00DC13F4  mov         esp,ebp                            //让esp指向ebp位置
00DC13F6  pop         ebp                                    //弹出ebp,
00DC13F7  ret                                                    //使其指向调用者调用函数之后的下一条指令的地址


00B81444  call        00B810E6                           //下一条指令地址出栈
00B81449  add         esp,8                                //将之前放入栈的两个实参从栈中移除,esp下移
00B8144C  mov         dword ptr [ebp-20h],eax     //将eax中的值30放入[ebp-20h]中,函数调用也到此结束
    14: return 0;

四、函数调用图


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值