什么样的堆栈展开库确实存在,有什么区别?

aby*_*s.7 7 c++ linux cpu-architecture llvm stack-unwinding

试图构建我自己的非GNU跨平台C++环境,我遇到的事实是我并不真正理解堆栈展开的基础知识.我构建的环境如下:

libc++libc++abilibunwind(或一些其他退绕).

我发现libc++abi已经包含某种libunwind,但是在Linux上没有使用它.从我理解的评论中,它是特殊的libunwind:LLVM Stack Unwinder只支持Darwin和ARM但不支持x86_64 - 而且令人困惑.CPU体系结构如何影响堆栈展开过程?

我也知道关于堆栈取消器:

  1. glibc内置.
  2. libc ++ abi LLVM libunwind.
  3. GNU libunwind(来自稀树草原).

问题:

  1. 平台或CPU架构如何影响堆栈展开过程?
  2. 为什么要有多个堆叠退绕器 - 而不仅仅是一个?
  3. 什么样的unwinders确实存在,它们之间有什么区别?

答案的期望:

我期望得到完整涵盖这个主题的答案,而不仅仅是每个问题上的单独点.

Tom*_*Tom 3

从根本上来说,堆栈布局取决于编译器。它几乎可以用它认为最好的任何方式来布局堆栈。语言标准没有提及堆栈的布局方式。

实际上,不同的编译器以不同的方式布置堆栈,并且相同的编译器在使用不同的选项运行时也可以以不同的方式布置堆栈。堆栈布局将取决于目标平台上类型的大小(尤其是指针类型的大小)、编译器选项(例如 GCC)-fomit-frame-pointer、平台的 ABI 要求(例如,x64 有定义的 ABI,而 x86 没有)。如何解释堆栈还取决于编译器如何存储相关信息。这反过来又部分取决于可执行文件格式(现在可能是 ELF 或 COFF,但实际上,只要操作系统可以加载可执行文件并找到入口点,其他一切都可以轻松获取),部分取决于调试信息格式 - 这又特定于所使用的编译器/调试器组合。最后,完全有可能编写内联汇编程序,以任何展开程序都无法遵循的方式操作堆栈和程序流。一些编译器还允许您自定义函数序言和结尾,为您提供了另一个混淆任何展开算法的机会。

所有这一切的最终结果是,不可能编写一个在任何地方都适用的单一堆栈展开算法。展开算法必须与编译器、操作系统相匹配,并且除了最基本的信息外,还必须与调试器相匹配。您能做的最好的事情就是编写一个简单的堆栈展开接口,并为您支持的每个编译器/操作系统/调试器组合以不同的方式实现它。