GCC的异常处理模型

16

GCC支持Setjump-longjump(sjlj)和基于Dwarf2表的取消(dw2)异常处理模型。这两种模型有什么区别,如何选择合适的模型?为什么Dwarf2表驱动的取消(dw2)是更高效的模型?我知道这两种模型不能混合使用。

参考文献:技术预览:gcc-4.2.1-sjlj -2

2个回答

17

对于每个函数,dwarf2会建立包含被调用者保存寄存器、它们在堆栈中保存的位置以及调用栈中帧指针/返回地址以及其他一些信息的表格。如果使用dwarf2,编译器可以利用这些信息有效地恢复寄存器,并在异常情况下跳回到调用者。后端需要在它们实现的序言生成代码中提供信息,告诉GCC哪些寄存器是被调用者保存的,并且何时保存帧指针等等。

使用setjmp / longjmp只是一种hack。由于setjmp / longjmp不知道抛出函数的结构,因此它将恢复由setjmp保存在跳转缓冲区中的所有寄存器,即使它们没有被抛出函数覆盖。我并不是这方面的专家,但很明显,这不是高效的。此外,每次启动try块时,都必须调用setjmp来设置包含保存寄存器的缓冲区,而使用dwarf2时,编译器已经在编译时提供了所有必要的信息。

如果后端没有提供必要的信息,则GCC将自动回退到基于setjmp / longjmp的异常处理。

注意,我不是GCC专家。我只是将工具链移植到我的教授所使用的某个简单处理器上,包括GCC。希望我能对你有所帮助。


请注意,http://www.nongnu.org/libunwind/ 存在,它具有一个高效的setjmp实现,其本身基于dwarf表。因此,setjmp只需要存储堆栈指针,剩下的交给已经工作的dwarf解缠器即可。 - Johannes Schaub - litb

11
避免使用sjlj。每个“try”块都会调用setjmp,这会保存寄存器,即使没有引发异常也会影响性能。使用表格,正常的控制流不会产生执行成本。只有在引发异常时,异常处理机制才需要查找表格以确定要做什么。

你好themis。我正在创建一个应用程序,我的主要编译器是mingw。我还使用MSVC创建DLL以访问只有MSVC可以编译的功能。从MinGw代码中,我在WM_CREATE的windowProcedure CALLBACK中创建了一个对象。如果出现错误,这个对象的构造函数会抛出异常;它正在这样做。创建窗口的代码位于try catch块中。然而,我没有看到异常被引发,我遇到了未定义的行为。你能推荐一本书来解释MinGw和MSVC异常的工作原理吗? - user13947194

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接