C++栈回溯原理

2021/10/27 22:11:04

本文主要是介绍C++栈回溯原理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

       我们在使用VS调试源代码或使用Windbg调试exe程序时,遇到异常,调试器就会中断下来,然后就能查看到此刻的函数调用堆栈。软件是执行到某一句机器代码产生了异常,可以看成执行了某一句汇编代码产生了异常,通过一句汇编代码,是如何将所在线程此刻完整的函数调用堆栈给回溯进来的呢?下面我们就来讲讲栈回溯的原理。

       要搞清楚栈回溯的原理,需要对照着函数调用时的栈分布情况来看:

1、函数入口处的汇编代码

        对照着上图,看一下函数入口的ebp和esp寄存器操作。

ebp - 函数栈基址寄存器,esp - 函数栈顶地址寄存器。函数占用的栈空间(地址范围)就在esp中的栈顶地址到ebp中的栈基址之间,函数的栈空间在函数入口处就进行分配了。

        在每个函数的入口处都会有下面两句代码:

push  ebp

mov  ebp,esp

       push的是主调函数的ebp,当前主调函数的栈顶地址esp,给被调函数ebp,即主调函数在调用函数时的栈顶地址就是被调函数的栈基址ebp。从栈内存分布来看,被调函数的栈基址,就是主调函数的栈基址值存放在栈内存上的内存地址。

2、函数退出处的汇编代码

       每个函数退出处都会有下面两句汇编代码:(return之前的汇编代码)

mov  esp,ebp

pop   ebp

       被调函数即将退出时,将自己(被调函数)的栈基址给主调函数的esp,即作为主调函数当前的栈顶地址。然后从栈中将主调函数的栈基址值拿出来,放到ebp寄存器中。

3、栈回溯的过程

       首先通过当前发生异常的那句汇编代码的地址(代码段地址),通过遍历当前程序中所有函数的地址范围,即可得知当前发生异常的汇编指令位于哪个函数中。

       就是以当前ebp寄存器中的值作为栈内存地址,该地址指向的栈内存中的4字节内容就是主调函数的栈基址值ebp(先记录着,为下一轮推算做准备),向下偏移4个字节的内存中存放着主调函数的返回地址,根据返回地址遍历当前程序中的函数地址范围,确定主调函数是哪个函数。

       上面得到了主调函数的栈基址ebp,依次向上推算,确定更上一层的主调函数,这样就将函数调用栈给回溯出来了。



这篇关于C++栈回溯原理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程