C++异常的幕后2:一个小ABI

原文地址:https://monoinfinito.wordpress.com/2013/02/12/c-exceptions-under-the-hood-ii-a-tiny-abi/

作者:nicolasbrailo 

如果我们准备尝试理解为什么异常是复杂的,以及它们如何工作,我们可以读大量的手册,也可以尝试自己编写异常的处理。实际上,我惊讶于这个议题好资料的缺乏:我找到的几乎所有东西要么非常详细,要么非常基础,只有一两个例外。当然,有一些要实现的规范(最值得注意的是C++的ABI,但我们还有CFI、DWARF与libstdc),但只阅读规范不足以真正理解底层。

让我们从最明显的开始:重新发明轮子!我们知道一个事实,C不能处理异常,因此让我们尝试使用一个C链接器链接一个抛出的C++程序,看会发生什么。我想出了这样一个简单的东西:

1

2

3

4

5

6

#include "throw.h"

extern "C" {

    void seppuku() {

        throw Exception();

    }

}

不要忘了extern,否则g++将重整我们小函数的名字,我们将不能将它与我们的C程序链接。当然,我们需要一个头文件来将C++世界与C世界“链接”(没有双关语)起来:

1

2

3

4

5

6

7

8

9

10

11

struct Exception {};

 

#ifdef __cplusplus

extern "C" {

#endif

 

    void seppuku();

 

#ifdef __cplusplus

}

#endif

以及一个非常简单的main:

1

2

3

4

5

6

7

#include "throw.h"

 

int main()

{

    seppuku();

    return 0;

}

如果现在我们尝试编译并链接这个代码会发生什么?

1

2

> g++ -c -o throw.o -O0 -ggdb throw.cpp

> gcc -c -o main.o -O0 -ggdb main.c

注意:你可以从我的github库里下载这个项目的完整源代码。

目前还好。G++与gcc都陶醉在它们的小世界里。然而一旦我们尝试链接它们,混乱接踵而至:

  1. > gcc main.o throw.o -o app
  2. throw.o: In function `foo()':
  3. Throw.cpp:4: undefined reference to `__cxa_allocate_exception'
  4. throw.cpp:4: undefined reference to `__cxa_throw'
  5. throw.o:(.rodata._ZTI9Exception[typeinfo for Exception]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
  6. collect2: ld returned 1 exit status

 

确实,gcc抱怨缺少C++符号。虽然这些是非常特殊的C++符号。检查最后一行错误:缺少用于cxxabiv1的vtable。定义在libstdc++中,cxxabi援引用于C++的应用程序二进制接口。因此现在我们了解到异常处理是在带有C++ABI定义接口的标准C++库的辅助下完成。

C++ ABI定义了一个标准二进制格式,因此我们可以在一个程序里将对象链接起来;如果我们使用两个编译器编译一个.o文件,这些编译器使用不同的ABI,我们将不能把.o文件链接进应用程序。ABI也将定义其他一些格式,例如执行栈回滚或异常抛出的接口。在这个情形里,ABI在C++与我们程序里其他某些处理栈回滚的库之间定义了一个接口(不一定二进制格式,只是一个接口),即ABI定义了C++特定的内容,因此它可与非C++库交谈:这使得在C++里能捕捉从其他语言抛出的异常,除了别的之外。

无论如何,链接器将我们指向幕后异常处理的第一层:一个我们必须自己实现的接口,cxxabi。在下一篇我们将开始我们自己的小ABI,就像定义在C++ ABI里那样。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值