不使用 ebp 实现堆栈回溯

Implementing stack backtrace without using ebp

当明确告知编译器不要使用 ebp 作为堆栈帧指针时,如何实现堆栈回溯?

这个问题的答案只出现在 What is the purpose of the EBP frame pointer register? 上接受的答案的评论中。

现代调试器甚至可以在使用 -fomit-frame-pointer 编译的代码中执行堆栈回溯。该设置是最近 gcc 中的默认设置。

gcc 将必要的堆栈展开信息放入 .eh_frame_hdr 部分。 See this blog post for more details。它也用于运行时异常。您会在 Linux 系统上的大多数二进制文件中找到它(使用 objdump -h)。 /bin/bash 约为 16k,而 GNU /bin/true 约为 572B,ffmpeg.

约为 108k

有一个 gcc 选项可以禁用它的生成,但它是一个 "normal" 数据部分,而不是 strip 默认删除的调试部分。否则,您无法通过没有调试符号的库函数进行回溯。该部分可能比它替换的 push/mov/pop 指令更大,但它的运行时成本几乎为零(例如 uop 缓存)。


我认为该部分中存储的信息是从 return 地址到堆栈帧大小的映射。由于每个 call 指令都会将后续指令的地址压入堆栈,因此您可以从该地址识别父调用者。不是将 ebp 压入栈帧链表 栈上,而是将下一个 return 地址的偏移量存储在 .eh_frame_hdr 中部分,因此可以在需要回溯的代码需要时使用它。