对于函数栈帧的解释

函数栈帧的预备知识
1.维护栈帧的两个寄存器esp(栈顶指针),ebp(栈底指针),其他寄存器还有eax,ebx,ecx,edx,edi,eax等
2.主函数main也是由其他函数调用的,具体是由编辑器确定(有兴趣的可以自行调试查看)
3.push指往栈顶上压一个元素,同时esp指向下一个内存块(一个内存块4个字节)
5.pop指在栈顶上释放一个元素,同时esp指向上一个内存块
4.栈区的使用习惯的由高地址向低地址使用

以一个简单的程序为例

 

目录

一、主函数的创建

二、test函数的创建


一、主函数的创建

我们知道主函数也是由其他函数调用的,我们可以画图理解

 我们选择调试进入反汇编,通过汇编语言理解主函数是怎么创建的

 主函数的创建对应的汇编语言部分

 第一步.push  ebp>>>>指在栈顶上压一个元素,它的值为ebp所储存的地址,同时esp往上一个内存块

执行前

 执行后

 可以看到,在执行第一句汇编语言后,esp指向了下一个地址(低地址方向),通过内存可知,该地址确实存储了ebp的地址(小端存储模式,应倒着读)。

我们可以画图形象的理解(对比原先图)

 接下来执行第二步.move     ebp,esp>>>>指的是把esp所储存的地址放到ebp之中

执行前

执行后

 

 我们可以看到,在执行之后,ebp所储存的地址变成了esp所储存的地址。二者所存储的地址指向了同一个内存块

 注意,这里它们的地址所指向的内存块储存了之前ebp的地址,这是保证在调用完函数之后还可以返回来。

第三步.sub  esp,0E4h>>>>指的是将esp所储存的地址减去0E4h(h是个符号,表示这个数是16进制),再赋给esp。

执行前

执行后 

 可以看到esp确实指向了先前地址减0E4后的地址

具体看图

 这是我们可以看到,ebp和esp已经开始维护新的内存空间,而这个实际上就是为主函数main函数在栈区上所开辟的空间。

第4,5,6步都是push>>>>>>指的是在栈顶上压上对应寄存器所存储的内容

执行前

执行后

可以看到,esp往低地址方向移动了3个单位,具体如图所示

这三个寄存器是干什么的我们先不用管它。只需要知道再函数调用和销毁的过程中有它们就行了。

第7步.lea  edi+FFFFFF1Ch>>>> edi+FFFFFF1Ch这个东西,如果在勾选显示符号名的话,可以看到实际上edi,[ebp-04Eh],指的是将[ebp-04Eh]这个值加载到edi中如图

如图所示

 

 而最后这3步,真正起作用的是最后一步

解释起来就是,在edi和ebp的范围内将39h这么多个内存块全部初始化为0CCCCCCCCh

 

执行前

执行后

 

 通过查看内存的方式可以了解到,ebp到edi这两个寄存器所储存的地址之间对应的内存空间

全部初始化成了CCCCCCCh,这就是为什么我们有时候看到的所谓随机值

 

 对应可画图这样理解

 这就是主函数main创建和初始化的过程

接下来我们观察一下局部变量的创建

 

因为这三步类似,所以统一说明即可

其对应的汇编语言翻译过来的意思就是将0Ah(10进制中的10),14h(10进制中的20),0这些值分别放进[ebp-8],[ebp-14h],[ebp-20h]之中,具体如图所示

 

二、test函数的创建

 

 这步执行的意思指的是将[ebp-14h](即变量b所表示的值)所指向的值放到eax那里去,

而下一步的意思是在栈顶上再压上eax,具体如图所示

 

而下面两行的意思是,将[ebp-8]的值放到ecx中,然后在栈顶上压上ecx,具体如图所示 

 这一步,实际上是在创建将a,b变量传给test函数对应的参数

即形参是原来变量的临时拷贝,这也是为什么在改变形参后不会影响原来的值

接下来这一步,翻译过来的意思是即将进入test函数,按F11进去,再按次F11即可进到test函数的创建

 这里实际上有些细节变化,这一次调试过程中由于我忘记截图内存看到这些变化(如果重新调试的化,产生的地址不一样,这意味着前面都得改,本人比较懒,有兴趣的话可以自己尝试下),所以这里就用画图的形式向大家展示这些细节

 

 可以看到,在F11进去后,尽管没有push,但esp仍向低地址方向移动了一个单位

接下来便是开始创建test函数

 接下来的几步与创建main函数的时候相似,这里便不再赘述。读者可依据上面main函数的创建自行分析

 执行完后的结果如图所示

 

, 

 接下来执行下边的步骤

这里第一条指令的意思是把[ebp+8] (即变量a的值)的值放到eax中,第二条指令是把[ebp+0Ch](即变量b的值)加上eax中的值在放到eax中。

第三条指令的意思是把eax中加起来的结果再放到[ebp-8]的地址所指向的内存块中,即变量C的位置

 下一步

这一个指令表示的意思是,把[ebp-8]对应空间所储存的内容放到eax中

这时我们注意到了下面的},这说明test函数已经执行完了。接下来的将test函数所占用的空间释放还给操作系统

这三句话的意思是将edi,esi,ebx的所指向的内容 分别弹出放到edi,esi,ebx中

同时esp向下移动三个单位,具体如图所示

 接下来继续执行下面的指令

 第一句指令的意思是,将ebp所储存的地址放到esp中,再将ebp此时所指向的值(此时的值为原来main函数是ebp的位置)弹出放到ebp中,同时esp再指向下一个单元,结果如图所示

 

 由于test函数不再由esp和ebp维护,则说则说明test函数所使用的栈空间已经还给了操作系统(但还没完全结束)

接下来是执行最后一条指令
 

ret这个指令 的作用是跳回原来的主函数中,而此时esp所指向的位置恰好是下一条指令的地址,具体如图

 

而这个指令的意思是,将esp的地址加8,则回到了main是esp所指向的位置

自此test函数的调用和回收便全部完成

也就是所谓函数栈桢

注:以上调试在vs2013进行,使用的编辑器不同,其调试结果可能有所差异

但大体逻辑是类似的

以上便是关于函数栈桢的解释

如有不恰当之处,望指正!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值