在不使用ebp的情况下实现堆栈回溯

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

对此的回答只是在对EBP帧指针寄存器的目的是什么的接受答案的评论中? 。

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

gcc将必要的stack-unwind信息放入.eh_frame_hdr部分。 有关详细信息,请参阅此博客文章 。 它也用于运行时exception。 您可以在Linux系统上的大多数二进制文件中找到它(使用objdump -h )。 /bin/bash约为16k,GNU /bin/true为572B, ffmpeg为108k。

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


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