详解函数栈帧的建立

6 篇文章 0 订阅
2 篇文章 0 订阅

 哈喽,大家好,我是情谊,今天我们来探讨一下函数栈帧的创建,下周我们进行函数栈帧的销毁讨论,话不多说,直接开始。

注意哦,我们使用的编译器是VS2013,在这个编译器中更方便我们了解函数栈帧的建立与销毁。而且我们还需要知道,在不同的编译器上函数栈帧的创立与销毁大体方向是一样的,但是还是有区别的。

开始了解函数栈帧之间,我们需要简单了解一下通用寄存器,通用寄存器是电脑CPU内部进行储存数据的小型存储区,用来存储参数,运算数据,运算结果等,通常包括:

  • eax: 通常用来执行加法,函数调用的返回值一般也放在这里面
  • ebx: 数据存取
  • ecx: 通常用来作为计数器,比如for循环
  • edx: 读写I/O端口时,edx用来存放端口号
  • esp: 栈顶指针,指向栈的顶部
  • ebp: 栈底指针,指向栈的底部,通常用 ebp+偏移量 的形式来定位函数存放在栈中的局部变量
  • esi: 字符串操作时,用于存放数据源的地址
  • edi: 字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作

我们还需要了解一下压栈和出栈,压栈:给栈顶放一个元素,出栈:从栈顶删除一个元素

今天我们主要看的是ebp(栈顶指针)和esp(栈底指针),这两个寄存器存放的是地址,这两个地址是用来维护函数栈帧的。我们今天以下面这个简单的代码进行演示:

我们知道,每一个函数的调用都会在栈区上创建一块空间,,所以在上面的代码中,我们会在栈区创建两个空间,用来调用main函数和Add函数,这两块空间我们称为调用函数的函数栈帧,进行维护空间的是我们上面所说的两个寄存器ebp和esp,正在调用哪个函数,这两个寄存器就在维护哪块空间的栈帧也可以理解为,这两个寄存器正在维护哪片空间,那我们就正在调用哪个函数。例子:我们在调用Add函数时,ebp和esp就在维护Add的那片空间。

我们在使用栈区的地址时,一般是先使用高地址,再使用低地址,所以,栈帧大体形状如下:

其次,由上面的程序调试窗口中的调用堆栈中看出,main函数其实也是被调用的,继续调试结束,我们可以看出main函数是被一个函数__tmainCRTStartup()内部调用,而__tmainCRTStartup()这个函数又是被mainCRTStartup函数调用,所以总的关系是mainCRTStartup调用__tmainCRTStartup(),而__tmainCRTStartup()调用main函数,我们在调试状态下点击鼠标右键,选择转为反汇编语言

转化为反汇编语言后,我们就可以看到我们写的代码对应的汇编代码了 ,下图就是main函数的转化汇编语言

 在main函数调用之前,已经有一个函数去调用它了,所以,前一个函数的栈帧已经创建好了

所以接下来,我们根据上面的汇编语言创建main栈帧,第一条语句是push   ebp,这个语句的意思是将ebp进行压栈,就是将ebp移到函数上面进行新的函数栈帧的建立,接下来的move指令是将esp的值给ebp,那么ebp指向的就是esp。

第三句中的sub   esp,0E4h就是将esp这个地址减去0E4h(相当于十进制的228),进而开辟的空间是main函数的栈帧。

接下来的三句push相当于在main函数上面压栈了三个元素,需要注意的是esp会随着压栈的增多而变化,就是压栈在往上面进行,那么esp始终将其包括在内,实现函数栈帧的维护。

第七句lea   edi,[ebp+FFFFFF1Ch]  (相当于lea  edi,[ebp+0E4h])是将[ebp+0E4h]这个地址放入edi内,接下来进行的三句是一起执行的作用是从edi从下开始39h的数据全部改为0CCCCCCCCh(其实就是到ebp截至),至此main函数的栈帧的搭建完成,接下来的就是程序的进行。

mov  dword ptr [ebp-8],0Ah  这一行就是给a变量创建空间,位置是ebp-8,接下来的b,c都是给变量创建空间,我们假设一个空格代表四个字节,所以a,b,c的值的位置分别如图

接下来就是调用Add函数的传参,mov  eax,dword ptr [ebp-14h],这个表示的是将 ebp-14h这个地址的数据(就是b)放进eax,但是eax没有,所以我们也要进行压栈,创建一个地址来接受b的值,同理,a的传参也是这样,将ebp-8的值传到ecx中

接下来的call指令的执行,首先压栈一个call指令的下一条指令的地址001CA2FA ,这个的作用是让Add函数调用完成后返回这个压栈的位置,然后我们就真正的来到Add函数的调用了

我们看到,Add函数的建立和main函数的建立是一致的,所以我们便不在多说。请看下图。

自此,函数栈帧的建立就完成了,下周,我们讨论函数栈帧的销毁,那么看到这里的小伙伴请点一个赞呗,你们的点赞就是对我的最大的支持!

如果在文中发现些许错误的话,请多多包含哦,下周我会继续努力,带大家了解一下函数栈帧的销毁。谢谢大家!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值