我想了解如何构建一个调用堆栈,就像gdb在运行backtrace命令时所做的那样。这是在一次采访中被问到的,我根据我对调用堆栈和堆栈框架的了解来回答这个问题。我认为这是使用堆栈指针,调用者的返回地址/指令并将其映射到可执行/汇编指令来完成的。我一直在寻找它是如何实际完成的,或者是对这个堆栈步行的一个很好的解释。我在google搜索中找到的所有信息都与微软API以编程方式相关,我正在寻找如何构建调用堆栈的通用解释。
答案 0 :(得分:1)
谷歌搜索引导我here。
考虑使用帧指针的非常简单的ix86
调用约定。每次调用例程时,下一条指令的地址都会被压入堆栈。在进入后立即调用例程执行push %ebp; mov %esp,%ebp
指令。然后,您将完全按照上面的页面布局。
假设您从常规foo
停止,从bar
调用,从baz
调用,从main
调用。
您检查%ebp
指向的两个单词。第一个单词是%ebp
的前一个值(我们称之为prev_ebp
,第二个是返回地址 - 指令指针bar
内的某个位置。
您现在检查prev_ebp
指向的两个单词。第一个是prev_prev_ebp
,第二个是返回地址 - 指令指针在baz
内的某处。
重复直到你到达main,你已经大致执行了GDB使用的程序。
有许多实际的复杂情况,例如不使用帧指针的帧,但您不应该理解: - )
答案 1 :(得分:0)
我不知道它是如何在gdb中完成的,但是这里有一个想法,如果你可以将所有jmp/call
指令及其目标地址保存在一个堆栈中,那么在任何时候你都会有一个完整的调用跟踪