GCC支持Setjump-longjump(sjlj)和基于Dwarf2表的取消(dw2)异常处理模型。这两种模型有什么区别,如何选择合适的模型?为什么Dwarf2表驱动的取消(dw2)是更高效的模型?我知道这两种模型不能混合使用。
GCC支持Setjump-longjump(sjlj)和基于Dwarf2表的取消(dw2)异常处理模型。这两种模型有什么区别,如何选择合适的模型?为什么Dwarf2表驱动的取消(dw2)是更高效的模型?我知道这两种模型不能混合使用。
对于每个函数,dwarf2会建立包含被调用者保存寄存器、它们在堆栈中保存的位置以及调用栈中帧指针/返回地址以及其他一些信息的表格。如果使用dwarf2,编译器可以利用这些信息有效地恢复寄存器,并在异常情况下跳回到调用者。后端需要在它们实现的序言生成代码中提供信息,告诉GCC哪些寄存器是被调用者保存的,并且何时保存帧指针等等。
使用setjmp / longjmp只是一种hack。由于setjmp / longjmp不知道抛出函数的结构,因此它将恢复由setjmp保存在跳转缓冲区中的所有寄存器,即使它们没有被抛出函数覆盖。我并不是这方面的专家,但很明显,这不是高效的。此外,每次启动try块时,都必须调用setjmp来设置包含保存寄存器的缓冲区,而使用dwarf2时,编译器已经在编译时提供了所有必要的信息。
如果后端没有提供必要的信息,则GCC将自动回退到基于setjmp / longjmp的异常处理。
注意,我不是GCC专家。我只是将工具链移植到我的教授所使用的某个简单处理器上,包括GCC。希望我能对你有所帮助。
setjmp
实现,其本身基于dwarf表。因此,setjmp
只需要存储堆栈指针,剩下的交给已经工作的dwarf解缠器即可。 - Johannes Schaub - litb