内容简介:作者:如果我们准备尝试理解为什么异常是复杂的,以及它们如何工作,我们可以读大量的手册,也可以尝试自己编写异常的处理。实际上,我惊讶于这个议题好资料的缺乏:我找到的几乎所有东西要么非常详细,要么非常基础,只有一两个例外。当然,有一些要实现的规范(最值得注意的是C++的ABI,但我们还有CFI、DWARF与libstdc),但只阅读规范不足以真正理解底层。让我们从最明显的开始:重新发明轮子!我们知道一个事实,C不能处理异常,因此让我们尝试使用一个C链接器链接一个抛出的C++程序,看会发生什么。我想出了这样一个简
作者: nicolasbrailo
如果我们准备尝试理解为什么异常是复杂的,以及它们如何工作,我们可以读大量的手册,也可以尝试自己编写异常的处理。实际上,我惊讶于这个议题好资料的缺乏:我找到的几乎所有东西要么非常详细,要么非常基础,只有一两个例外。当然,有一些要实现的规范(最值得注意的是C++的ABI,但我们还有CFI、DWARF与libstdc),但只阅读规范不足以真正理解底层。
让我们从最明显的开始:重新发明轮子!我们知道一个事实,C不能处理异常,因此让我们尝试使用一个C链接器链接一个抛出的C++程序,看会发生什么。我想出了这样一个简单的东西:
1 2 3 4 5 6 |
|
不要忘了extern,否则g++将重整我们小函数的名字,我们将不能将它与我们的C程序链接。当然,我们需要一个头文件来将C++世界与C世界“链接”(没有双关语)起来:
|
|
以及一个非常简单的main:
|
|
如果现在我们尝试编译并链接这个代码会发生什么?
|
|
注意:你可以从我的 github库 里下载这个项目的完整源代码。
目前还好。G++与gcc都陶醉在它们的小世界里。然而一旦我们尝试链接它们,混乱接踵而至:
> gcc main.o throw.o -o app throw.o: In function `foo()': Throw.cpp:4: undefined reference to `__cxa_allocate_exception' throw.cpp:4: undefined reference to `__cxa_throw' throw.o:(.rodata._ZTI9Exception[typeinfo for Exception]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info' 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里那样。
以上所述就是小编给大家介绍的《[译]C++异常的幕后2:一个小ABI》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。