当明确告知编译器不使用ebp作为堆栈帧指针时,如何实现堆栈回溯?
答案 0 :(得分:2)
对此问题的回答只是对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选项可以禁用生成它,但它是一个“普通”数据部分,而不是strip
默认删除的调试部分。否则,您无法通过没有调试符号的库函数进行回溯。该部分可能比它替换的push/mov/pop
指令更大,但它的运行时成本几乎为零(例如uop缓存)。
我认为该部分中存储的信息是从返回地址到堆栈帧大小的映射。由于每条call
指令都将下一条指令的地址压入堆栈,因此您可以从该地址中识别父调用方。而不是推动ebp
在堆栈上创建堆栈帧的链接列表,下一个返回地址的偏移量存储在.eh_frame_hdr
部分,因此可以使用它如果需要回溯的代码需要。