上次我们编写的小ABI版本11能够处理相当多处理异常的基本情况:我们有一个(几乎奏效的)能够抛出与捕捉异常的ABI,但它仍然不能正确运行析构函数。如果我们希望编写异常安全代码,这相当重要。通过我们对.gcc_except_table的了解,运行析构函数小菜一碟,我们只需看一点汇编:
|
|
在一个规范的着陆垫上,当一个活动有大于0的类型索引时,它意味着我们看到类型表的一个索引,我们可以使用它来了解该catch可以处理哪些类型;对于具有值0的类型索引,这意味着我们看到一个清理块,无论如何都要运行它。虽然着陆垫不能处理异常,它将仍然能够执行清理,在回滚时这预期发生。当然,在完成清理时,着陆垫将调用_Unwind_Resume,这将继续正常的栈回滚过程。
我已经将这个最新版本上传到我的githut repo里,不过有有些新的坏消息:记得我们如何通过说uleb128 == char来欺骗的吗?一旦我们开始增加块来运行析构函数,.gcc_except_table开始变得相当大(“大”意味着我们有超过127字节长度的偏移),这个假设不再成立。
对这个ABI的下一个版本,我们必须重写读LSDA的函数来读正确的uleb128码。不是一个大的改动,但此时我们不会有太大的收获,我们已经实现了我们的目标:一个无需libcxxabi辅助能够处理异常的工作的最小ABI。
存在我们还没涉及的部分,像处理非原生异常,捕捉衍生类型以及编译器与链接器间的互操作。也许在其他时间,在这个相当长的系列里,我们已经学到相当多的了C++里底层如何处理异常的知识。