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

  原码如下:

#include <stdio.h>  
#pragma warning (disable:(4996))
int Add(int x,int y)  
{  
    int sum = 0;  
    sum = x+y;  
    return (sum);  
}  
int main()  
{  
    int a = 2;  
    int b = 3;  
    int ret = 0;  
    ret = Add(a,b);  
    return 0;  
  
  
} 


 基本的汇编指令: 

esp:esp寄存器里存储的是在调用函数之后,栈的栈顶。并且始终指向栈顶。
ebp:ebp寄存器里存储的是是栈的栈底指针,通常叫栈基址,这个是一开始进行函数调用之前,由esp传递给ebp的。(在函数调用前你可以这么理解:esp存储的是栈顶地址,也是栈底地址。)
push:压入操作,把一个32位的操作数压入堆栈中,这个操作在32位机中会使得esp被减4(字节),esp通常是指向栈顶的,这里顶部是地址小的区域,那么,压入堆栈的数据越多,esp也就越来越小
mov:数据传送。第一个参数是目的操作数,第二个参数是源操作数,就是把源操作数拷贝到目的一份。

sub:创建空间。

lea:load effective address 加载有效地址。

rep stos:重复指令


 转到反汇编之后:

1.当_tmainCRTStartup 还没有调用main函数时,esp,ebp共同维持并为_tmainCRTStartup开辟一个空间,

如下图所示:



2.开始调用main函数:

汇编代码如下:



(1)执行第一条指令: push       ebq//压栈,将ebp放入栈顶,而esp始终指向栈顶,如下图所示:


 

(2)执行第二条指令:mov       ebp,esp//将esp赋予ebp,ebp和esp指向同一位置,如下图所示:


(3)执行第三条指令:sub         esp,0E4h //将esp减去0E4h,0E4h是十六进制数,由于开辟的栈空间由高到低,所以esp往上走0E4h,如下图所示:


(4)执行指令:push        ebx  
                           push        esi  
                           push        edi//ebx,esi,edi三个寄存器进行压栈,main空间增大,如下图所示:


(5)执行指令:lea         edi,[ebp-0E4h] //[ebp-0E4h]是ebx,将ebx的地址传到edi中
                          mov         ecx,39h //将39h传到ecx寄存器中
                          mov         eax,0CCCCCCCCh //将0CCCCCCCCh传到eax寄存器中
                          rep stos    dword ptr es:[edi] //将栈上[ebp-0E4h]的位置开始向高地址的内存赋值0CCCCCCCCh,次数为0x39,0CCCCCCCCh代表未初始化。

如下图所示:



以上是main函数的调用。

以下是自己写的代码,转换成汇编代码:


指令 : mov         dword ptr [a],2 /*dword   双字 就是四个字节ptr     pointer缩写 即指针,[]里的数据是一个地址值,这个地址指向一个双字型数据。即将地址a指向的四字节数据2移动到ebp-4*/

指令:mov         dword ptr [b],3 //与上指令功能相似

指令: mov         dword ptr [ret],0 //与上指令功能相似

指令:mov         eax,dword ptr [b] //将变量b的值赋给eax

           push        eax  //将eax压栈

指令:mov         ecx,dword ptr [a] 
          push        ecx  

指令:call        @ILT+215(_Add) (0F810DCh) //call指令下一条指令的地址

指令效果如图所示:



Add函数汇编代码如下:


指令:

  push        ebp  //ebp压栈
  mov         ebp,esp //将esp传给ebp
  sub         esp,0CCh //给add函数开辟空间
  push        ebx  
 push        esi  
  push        edi  //将ebx,esi,edi三个寄存器压栈,add函数空间增大
  lea         edi,[ebp-0CCh] 
  mov         ecx,33h 
  mov         eax,0CCCCCCCCh 
  rep stos    dword ptr es:[edi]   //将从[ebp=0CCh]的地址位置开始向高地址内存空间赋值0CCCCCCCCh ,次数为33h
 mov         dword ptr [sum],0   //给sum赋值0

  mov         eax,dword ptr [x] //将x处的值传给eax
  add         eax,dword ptr [y] 
  mov         dword ptr [sum],eax   //将eax的值传给sum
 mov         eax,dword ptr [sum] 将sum的值存在寄存器eax中

指令效果如图:


出栈汇编代码:


指令:

 pop         edi  
 pop         esi  
pop         ebx  //三个寄存器出栈
mov         esp,ebp //将esp栈顶下移
pop         ebp  //将ebp出栈,此时下面还有一个ebp

 ret   //回到call指令的下一条指令    

add    esp,8//esp向下跳两格

 mov         dword ptr [ret],eax //将eax的值传给ret处。

xor         eax,eax  //异或运算,相同返回0,相反返回1;  

指令效果如下:


函数的调用过程,栈帧的创建和销毁已经完成。


   


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值