搞懂函数调用前后堆栈恢复的过程

您所在的位置:网站首页 栈指针的变化 搞懂函数调用前后堆栈恢复的过程

搞懂函数调用前后堆栈恢复的过程

2024-07-16 00:55| 来源: 网络整理| 查看: 265

零、基本概念

1、ESP

栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的顶部。

2、EBP

基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

一、栗子

以下摘自网上一篇文章: 

明白了吗?主要是用来保存 / 恢复堆栈,以便传递参数给函数。  在 MASM 里面,有一条更方便的语句,就是 invoke,使用它后,你就不用自己做这些事情了。 

总的来说,esp 始终指向栈顶,ebp 是在堆栈中寻址用的。

我的理解:

调用一个函数时,先将堆栈原先的基址(EBP)入栈,以保存之前任务的信息。然后将栈顶指针的值赋给 EBP,将之前的栈顶作为新的基址(栈底),然后再这个基址上开辟相应的空间用作被调用函数的堆栈。

函数返回后,从 EBP 中可取出之前的 ESP 值,使栈顶恢复函数调用前的位置;再从恢复后的栈顶可弹出之前的 EBP 值,因为这个值在函数调用前一步被压入堆栈。这样,EBP 和 ESP 就都恢复了调用前的位置,堆栈恢复函数调用前的状态。

二、通过 ollydbg 跟踪 esp 和 ebp

这里写图片描述

可以看到,初始情况下,ebp 此时值为 0012FEDC,也就是栈帧的地址,而栈顶地址 esp 值为0012FDFC。可以看到两个值有一定的关系。而帧指针的地址较高。

然后我们让它执行前两句,push ebp,mov ebp,esp这里写图片描述

可以看到前两句已经执行了,那么 ebp 跟 esp 的值也发生了变化。esp = 0012FDF8,ebp = 0012FDF8。为神马?一句句解读,push ebp,向栈里面压入了一个东西,那么栈顶此时应该发生变化了,也就是地址 -4 字节。为什么是减法呢?因为是向低地址增长的,这点一定得注意。所以此时 esp 变化成了 0012FDFC - 4 = OO12FDF8。至于 ebp 也等于 0012FDF8 就不解释了。

接着上图不解释:这里写图片描述

此时呢,观察现在的值。栈顶 esp = 0012FDF4,而 ebp = 0012FDF8;没啥好说的,此时的栈顶已经又跑上去了,说明又有元素压栈了。那么执行这句 mov esp, ebp 之后,不用说,esp 跟 ebp 都会变成 0012FDF8.

我们重点看下一幅,执行完 pop,让 ebp 出栈,后会发生神马。

这里写图片描述 此时 ebp 已经出栈了,来看看那他们的值,esp = 0012FDFC,ebp = 0012FEDC。首先,ebp 出栈了,这个时候栈空了,所以栈顶会变成初始时的值 0012FDFC。相当于上图中的 esp = 0012FDF8 + 4 = 0012FDFC。注意出栈,则栈顶 + 4,然后呢。ebp 为啥变成了 0012FEDC 初始的值?ebp 不是一直保存着 esp 的初始地址么?

所以重点就在 pop 这个语句了。pop ebp 究竟表达神马意思?ebp 的值起初存在了栈中,出栈以后,它的值就恢复了原样。所以这一句灰常重要啊。pop 的意思也许就是把弹出的值赋给我们的变量,pop ebp,也就是把存在栈中的值弹出来赋给 ebp。

三、流程图

EBP 和 ESP 后面的序号是两个寄存器各自更新的次序。  

四、总结

1、两句的 mov ebp,esp 实际上是把 ebp 进栈后的栈顶地址给了 ebp。 2、在 ebp 没有出栈钱,它会一直保存 ebp 进栈以后的栈顶值,也就是 1 的值。 3、在 ebp 出栈前,需要把 esp 恢复到只有 ebp 在栈中时的值。 4、出栈后,esp 自然恢复到 ebp 进栈以前的初始值,而 pop ebp 则恢复了 ebp 的初始值。 5、pop 的语义很重要,pop ebp 的意思是把当前栈顶的元素出栈,送入 ebp 中,而不是让 ebp 出栈,这点必须明确!

转载于:EBP 和 ESP 详解_测试开发小白变怪兽-CSDN博客_ebp

(SAW:Game Over!)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3