个人主页:欢迎大家光临——>沙漠下的胡杨

各位大帅哥,大漂亮

如果觉得文章对自己有帮助

可以一键三连支持博主

你的每一分关心都是我坚持的动力

☄: 本期重点:我们今天讲解下函数栈帧的形成和销毁

希望大家每天都心情愉悦的学习工作

☄: 本期重点:我们今天讲解下函数栈帧的形成和销毁

相关的寄存器:

相关的汇编命令:

首先我们了解下C程序地址空间(VS版)

接着我们看下函数调用的逻辑

下面我们以一个简单的例子来进行理解:

创建main函数栈帧

分析main函数中的代码

调用MyAdd函数前的准备:

进行函数调用:

开辟MyAdd的栈帧空间:

分析MyAdd代码

准备返回

ret之后

返回call的下一条指令处

剩下一个有意思的证明:

本篇总结:

下期预告:


函数栈帧讲解我们通过汇编的一些分析讲解,所以我们先了解下一些寄存器和汇编指令来进一步学习栈帧吧。

相关的寄存器:

eax:通用寄存器,保留临时数据,常用于返回值

ebx:通用寄存器,保留临时数据

ebp:栈低寄存器

esp:栈顶寄存器

eip:指令寄存器,保留当前指令的下一条指令地址。

相关的汇编命令:

mov:数据转移指令

push:数据入栈,同时esp栈顶寄存器发生改变

pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变

sub:减法命令

add:加法命令

call:函数调用 1.压入返回值 2.转入目标函数

jmp:通过修改eip,转入目标函数,进行调用

ret :恢复返回值地址,压入eip,类似pop eip命令

首先我们了解下C程序地址空间(VS版)

C程序地址空间的图如下:

先看a变量,是把 0A的值赋给 ebp – 8这个空间,同理 b 和 z 也是。

看图解:

首先是把ebp – 14h(变量b的值)的值放入eax中,其实就是b的值放入寄存器中,然后压入eax,同理压入ebp – 8(变量 a的值)。

看示意图,观察此时的寄存器的指向,最下面为内存布局:

上面的过程证明了:

1.函数调用前,就已经形成了临时变量。

2.形参实例化的顺序是从右向左的。

进行函数调用:

执行 call 命令,进入函数体内。

call要做的是 :

1:压入返回值 2.转入目标函数

为什么要压入返回值呢?因为函数可能会调用结束,那么就需要返回了。

压入返回值,就是压入 call 指令的下一条指令的地址。

看下压入前的内存和地址:

另外说一下,jmp 后的值,就是MyAdd函数的地址,就是跳转到该函数处。

所以eip的值也就由原来的 main函数值 变为 MyAdd函数的值啦。

看示意图:

这些汇编就是为MyAdd开辟战帧空间

首先逐步分析,push ebp,把ebp压入栈中,ebp就是main函数的栈低位置,mov 把 esp的地址移动到ebp中,ebp其实是MyAdd的栈顶,最后把 esp 的值减去0CC。其实就是把esp的当前位置向上移动,然后和 ebp 围成一段空间,为了MyAdd函数使用。

如图所示:

其中 ebp 和 esp围成的空间就是MyAdd函数的栈帧。

这是 esp 和 ebp 都指向了,main函数的栈顶,那么栈低指针呢?

不用担心main函数栈低的地址找不到,我们刚才把main函数栈低指针压入了MyAdd的栈帧空间中啦,到时候可以直接返回了。

分析MyAdd代码

还是先进行反汇编代码查看:

逐个分析:

mov ebp – 8, 0,其实就是在ebp -8的位置处赋值为0,接着把 ebp + 8的值放入eax中,再把ebp + 0C 的值和原来eax中的值相加,最后把eax中的值放入ebp – 8空间中去

翻译下就是:

开辟空间 c 变量,初始化为0,把原来形参实例化中的a的值放入eax中,把形参实例化中的b也放进去与a相加,最后的结果在eax中,把eax的值放入变量 c 的空间中。这就是上述的汇编。下面看下示意图:

接着我们继续分析汇编:

分析下:首先是把变量 c 的值放入eax寄存器中,接着我们弹出edi,esi,ebx这些都不管,重点看下,mov esp ,ebp这句代码,这个就是把ebp的地址赋值给esp,相当于esp 和 ebp同时指向了MyAdd的栈低处,也就是释放了栈帧空间, 然后pop ebp,就是弹栈,ebp处是栈底,栈底就是main函数的栈底,也就是说pop后,ebp又回到了main函数的栈底,而esp就在call的下一条指令处啦。

如图所示:

返回call的下一条指令处

我们ret之后返回到了call的下一条指令处

接着看汇编,把esp的值加 8 ,其实就是把所形成的临时变量销毁。

把eax的值移动到 ebp- 20,其实上就是把寄存器中0xC的值移动到变量z中去。

看示意图:

本篇总结:

首先我们从汇编底层来看和了解了函数栈帧的创建和销毁,其中每个细节,每个汇编指令做出了解释和相对性的示意图,希望大家有所收获吧。

下期预告:

下期会更新可变参数列表的相管内容