LLVM异常处理实现

Pup*_*ppy 17 llvm

请注意,我已经阅读了这些 问题并阅读了博客文章,我也引用了ABI.

我完全不理解的是它与LLVM的EH内在函数的交互方式.LLVM EH页面给出了一个非常模糊的概述 - 不完全是"实现X,Y,Z"的清单.

LLVM EH页面直接引用安腾ABI.这意味着LLVM只支持Itanium ABI异常.但我已经知道Clang支持ARM并且正在开发对Microsoft ABI的支持.那么LLVM对Itanium ABI的EH实现究竟有多具体?

当引用Itanium ABI定义的_Unwind内容时,是否必须由后端提供,或者我是否必须为自己实现?

我还注意到Clang生成的LLVM IR没有显示任何特定于语言的表,任何异常帧,异常表或类似的东西.在这种情况下,LLVM如何知道如何生成特定于语言的数据?

简而言之,你究竟是如何从LSDAs,EH背景,_Unwind_RaiseExceptionlandingpadresume

编辑:仅供参考,我将在Windows上JITting生成的代码.

Nik*_*lai 7

如今,安腾 C++ ABI 已成为许多其他平台上使用的事实上的标准 C++ ABI。Itanium C++ ABI 支持零成本异常处理技术,这是当今最普遍的技术。

为了支持异常处理,必须改变函数调用的语义。现在调用分支执行流程。当一切正常时采用一个分支,在异常情况下采用第二个分支。在 LLVM IR 中有invoke调用可能抛出的函数的指令。

当采取第二个分支时,可能会执行多种操作:

  • 调用析构函数(清理
  • 继续堆栈展开(恢复
  • 强制抛出规范(过滤器
  • 恢复正常的控制流(catch)。

很明显,必须生成一些额外的代码来执行这些操作。这就是为什么我们也得到了landingpad指令。它是以invoke异常结束后要执行的第一条指令。

但是主要的魔法是在运行时执行的。抛出异常后,语言不可知运行时展开堆栈,对于每一帧,它都会找到语言特定数据区 (LSDA) 并调用语言特定个性例程。个性例程检查程序计数器、LSDA 和当前异常。它确定是否需要进行任何清理,是否违反了任何抛出规范,或者该帧是否可以捕获异常。

您可能知道,所有这些数据(个性例程、捕获类型、抛出规范、清理操作)都已在landingpad 指令中指定,因此不应向后端传递额外数据以在目标文件中生成与异常相关的部分。


Pup*_*ppy 5

简短的回答是,LLVM 有效地硬编码了它想要支持的每个 EH ABI(ARM、Itanium、SEH 等)的支持。因此,虽然这些内容landingpad在理论上可能有些抽象,但它实际上根本不抽象并且非常紧密耦合,因为您需要做的另一半工作必须由您需要显式执行的 Itanium ABI EH 支持库来完成。

LLVM 几乎生成所有 EH 实现细节,但您还必须在运行时链接到 Itanium EH 支持库。除此之外,IR 确实如其所显示的那样——程序员不需要做任何额外的工作。

我想如果您想使用非安腾,事情会变得更加棘手。