繁体   English   中英

C++异常处理如何转化为机器码

[英]How does C++ exception handling translate to machine code

在心理上,我一直想知道 try/throw/catch 在幕后的样子,当 C++ 编译将其转换为汇编程序时。 但是因为我从来没有用过它,所以我从来没有时间去检查它(有些人会说懒惰)。

是用于跟踪try的普通堆栈,还是单独为此目的保留的单独的每线程堆栈? MSVC和g++之间的实现是大还是小? 请给我看一些伪 asm(IA-32 也可以),这样我就不必自己检查了! :)

编辑:现在我了解了 MSVC 在 IA-32 处理上的实现基础知识。 有人知道 IA-32 上的 g++ 或任何其他 CPU 吗?

编辑 2(11 年后): 以下是一些性能数据。 他们还免费提供源代码

异常处理程序的糟糕实现在进入 try 子句时为每个 try 子句在运行时堆栈上推送某种异常处理程序块,并在退出 try 子句时将其弹出。 还维护保存最近推送的异常处理程序块的地址的位置。 通常,这些异常处理程序链接在一起,因此可以通过从最新版本到旧版本的链接找到它们。 发生异常时,会找到指向最后推送的 EH 处理程序块的指针,并检查对该“try”子句的 EH 情况的处理。 击中 EH 情况会导致堆栈清理发生回到推送 EH 的点,并且控制转移到 EH 情况。 没有命中 EH 会导致找到下一个 EH,并重复该过程。 Windows 32 位 SEH 方案是此方案的一个版本。

这是一个糟糕的实现,因为即使没有发生异常,程序也会为每个 try 子句(push then pop)付出运行时代价。

好的实现只是简单地记录一个范围表,其中出现了 try 子句。 这意味着进入/退出 try 子句的开销为零。 (我的PARLANSE并行编程语言使用这种技术)。 异常在表中查找异常点的PC,将控制权交给表选择的EH。 EH 代码根据需要重置堆栈。 又快又漂亮。 我认为Windows 64位EH是这种类型,但我没有仔细看。

[编辑 2020 年 4 月:最近刚刚测量了 PARLANSE 异常的成本。 如果没有例外,则为 0nS(按设计); 25ns 在 3Ghz i7 上从“抛出”到“捕捉”到“确认”(结束空捕捉)。 OP 为最简单的类型添加了一个大约 1000ns 的测量 C++ 异常处理的链接,以及一个真正的非标准处理方案,在 57ns 处记录异常或无异常; C++ 版本的 CPU 时钟速率稍慢,因此这些数字仅用于粗略比较。]

这是一篇关于该主题的非常有价值的文章: C ++编译器如何实现异常处理

微软期刊的“Under the Hood”系列在1997年对这个主题进行了深入研究:

关于Win32™结构化异常处理深度的速成课程

C++ 标准委员会发布了一份关于“C++ 性能”的技术报告,以揭穿许多关于 C++ 特性如何减慢你的神话。 这还包括有关如何实现异常处理的详细信息。 本技术报告草稿可免费获取。 检查第 5.4.1 节。 “异常处理实施问题和技术”。

来自Godbolt 编译器资源管理器的Asm ,用于 x86-64 System V 调用约定,使用 g++8.2 的 C++ABI,用于捕获函数和抛出函数。

x86-64 System V 将.eh_frame部分用于堆栈展开元数据,因此异常帮助程序库函数知道如何遍历堆栈并恢复寄存器。 这就是.cfi指令所做的。

看看这个很好地描述异常处理内部的文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM