搞懂函数调用前后堆栈恢复的过程 |
您所在的位置:网站首页 › 栈指针的变化 › 搞懂函数调用前后堆栈恢复的过程 |
零、基本概念
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 |