[译]C++异常的幕后6:gcc_except_table与personality函数

栏目: 服务器 · 编程工具 · 发布时间: 6年前

内容简介:上次我们了解到,就像throw语句被翻译为一对__cxa_allocate_exception/throw调用,catch块被翻译为一对__cxa_begin/end_catch调用,加上称为CFI(调用帧信息)的对象,来查找着陆垫——函数处理异常之处。我们尚不知道的是_Unwind_如何知道着陆垫在哪里。在一个异常被抛出时,栈上有一组函数;所有CFI内容将让Unwind知道这些是什么函数,但知道每个函数提供哪些着陆垫也是必须的,因此我们可以调用每个函数,核查它是否希望处理这个异常(我们忽略带有多个try/

作者: nicolasbrailo  

上次我们了解到,就像throw语句被翻译为一对__cxa_allocate_exception/throw调用,catch块被翻译为一对__cxa_begin/end_catch调用,加上称为CFI(调用帧信息)的对象,来查找着陆垫——函数处理异常之处。

我们尚不知道的是_Unwind_如何知道着陆垫在哪里。在一个异常被抛出时,栈上有一组函数;所有CFI内容将让Unwind知道这些是什么函数,但知道每个函数提供哪些着陆垫也是必须的,因此我们可以调用每个函数,核查它是否希望处理这个异常(我们忽略带有多个try/catch块的函数)。

要知道着陆垫在哪里,要使用称为gcc_except_table的东西。在函数末尾可以找到这(带有一组CFI):

1

2

3

4

5

6

.LFE1:

    .globl  __gxx_personality_v0

    .section    .gcc_except_table,"a",@progbits

    [...]

.LLSDACSE1:

    .long   _ZTI14Fake_Exception

节.gcc_except_table是所有定位着陆垫信息保存的地方,一旦我们设法分析了personality函数后,我们再来更多地了解它;目前,我们只是说LSDA表示语言特定数据区域,它是personality函数检查对一个函数是否存在任何着陆垫的地方(在回滚栈时,它也用于运行析构函数)。

总之:对每个至少找到一个catch的函数,编译器将把这个语句翻译为一对__cxa_begin_catch/ __cxa_end_catch调用,接着personality函数,被__cxa_throw调用,将为栈上每个函数读gcc_except_table,查找称为LSDA的东西。然后Personality函数将在LSDA里检查一个catch是否能处理一个异常,是否有清理代码运行(这就是在需要时触发析构函数的原因)。

这里我们还可以得到一个有趣的结论:如果我们使用nothrow说明符(或者空的throw指示符),编译器可以为这个方法忽略gcc_except_table。Gcc实现异常的方式,不会对性能产生大的影响,但确实将减小代码大小。Catch是什么?如果在指明nothrow时抛出一个异常,不存在LSDA,personality函数不知道怎么做。在personality函数不知道做什么时,它将调用缺省的异常处理句柄,意味着在大多数情形里从一个nothrow方法抛出将最终调用std::terminate。

现在我们了解了personality函数是什么,我们可以实现它吗?下一节我们来看如何做。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

未来简史

未来简史

[以色列] 尤瓦尔·赫拉利 / 林俊宏 / 中信出版集团 / 2017-2 / 68.00元

进入21世纪后,曾经长期威胁人类生存、发展的瘟疫、饥荒和战争已经被攻克,智人面临着新的待办议题:永生不老、幸福快乐和成为具有“神性”的人类。在解决这些新问题的过程中,科学技术的发展将颠覆我们很多当下认为无需佐证的“常识”,比如人文主义所推崇的自由意志将面临严峻挑战,机器将会代替人类做出更明智的选择。 更重要的,当以大数据、人工智能为代表的科学技术发展的日益成熟,人类将面临着从进化到智人以来z......一起来看看 《未来简史》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试