尝试构建我自己的非GNU跨平台C ++环境,我遇到了一个事实,即我并不真正理解堆栈展开的基础知识。我构建的环境如下:
libc++
←libc++abi
←libunwind
(或其他一些开卷)。
我发现libc++abi
已经包含某种libunwind,但在Linux上没有使用它。从我理解的评论中,它是特殊的libunwind:LLVM Stack Unwinder只支持Darwin和ARM但不支持x86_64 - 而且令人困惑。 CPU体系结构如何影响堆栈展开过程?
我也知道关注堆栈取消器:
我希望得到的答案涵盖整个主题,而不仅仅是每个问题上的单独点。
答案 0 :(得分:2)
从根本上说,堆栈布局取决于编译器。它可以以几乎任何它认为最好的方式布置堆栈。语言标准没有说明堆栈的布局。
在实践中,不同的编译器以不同的方式放置堆栈,并且当使用不同的选项运行时,相同的编译器也可以不同地进行布局。堆栈布局将取决于目标平台上类型的大小(尤其是指针类型的大小),编译器选项(如GCC' s -fomit-frame-pointer
),平台的ABI要求(例如x64具有已定义的ABI)其中x86没有)。如何解释堆栈还取决于编译器如何存储相关信息。这反过来部分取决于可执行格式(现在可能是ELF或COFF,但实际上,只要操作系统可以加载可执行文件并找到入口点,其他一切都非常适合抓取),部分取决于调试信息格式 - 再次特定于正在使用的编译器/调试器组合。最后,完全可以编写内联汇编程序,以 no unwinder将能够遵循的方式操作堆栈和程序流。一些编译器还允许您自定义函数序言和结尾,为您提供另一个混淆任何展开算法的机会。
所有这一切的净效果是无法编写可在任何地方使用的单个堆栈展开算法。展开算法必须匹配编译器,OS以及调试器以外的最基本信息。您可以做的最好的事情是编写一个简单的堆栈展开接口,并为您支持的每个编译器/ OS /调试器组合实现不同的接口。