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

2021-12-18 00:00:00 exception assembly try-catch c++

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

Mentally, I've always wondered how try/throw/catch looks behind the scenes, when the C++ compiles translates it to assembler. But since I never use it, I never got around to checking it out (some people would say lazy).

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

Is the normal stack used for keeping track of trys, or is a separate per-thread stack kept for this purpose alone? Is the implementation between MSVC and g++ big or small? Please show me some pseudo asm (IA-32 is ok too) so I never have to check it out myself! :)

现在我了解了 MSVC 在 IA-32 处理方面的基本实现.有人知道 IA-32 上的 g++ 或任何其他 CPU 吗?

Now I get the basics of MSVC's implementation on IA-32 handling. Anybody know for g++ on IA-32, or any other CPU for that matter?

编辑 2(11 年后): 这里是一些关于性能的数据.他们还免费提供了源代码.

Edit 2 (11 years later): Here are some data on performance. They've also made source code freely available.

推荐答案

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

Poor implementations of exception handlers push some kind of exception handler block for each try clause on the runtime stack as the try clause is entered, and pop it off as the try clause is exited. A location holding the address of the most recently pushed exception handler block is also maintained. Typically these exception handlers are chained together so they can be found by following links from the most recent to older versions. When an exception occurs, a pointer to the last-pushed EH handler block is found, and processing of that "try" clause's EH cases is checked. A hit on an EH case causes stack cleanup to occur back to the point of pushed EH, and control transfers to the EH case. No hits on the EH causes the next EH to be found, and the process repeats. The Windows 32-bit SEH scheme is a version of this.

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

This is a poor implementation because the program pays a runtime price for each try clause (push then pop) even when no exception occurs.

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

Good implementations simply record a table of ranges where try clauses occur. This means there's zero overhead to enter/exit a try clause. (My PARLANSE parallell programming langauge uses this technique). An exception looks up the PC of the exception point in the table, and passes control to the EH selected by the table. The EH code resets the stack as appropriate. Fast and pretty. I think the Windows 64 bit EH is of this type, but I haven't looked carefully.

相关文章