C ++异常和.eh_frame ELF部分

时间:2015-10-09 09:47:23

标签: c++ exception gcc exception-handling elf

.eh_frame ELF部分的缺失或损坏是否导致我的C ++代码中的异常停止工作?之前成功捕获的任何异常现在都在调用std :: terminate()。

我的情况:

  1. 我的zzz.so共享库有try-catch块:

    try {
        throw Exc();
    } catch (const Exc &e) {
        LOG("ok " << e.what());
    } catch (...) {
        LOG("all");
    }
    
  2. 加载zzz.so的可执行文件(使用ldopen)。它在zzz.so

  3. 中调用一个函数
  4. zzz.so中抛出的所有异常都成功捕获到zzz.so中并转储到我的日志文件中
  5. 还有另一个aaa.so加载到另一个二进制文件中。另一个aaa.so正在加载我的zzz.so。
  6. zzz.so中抛出的所有相同异常都会导致调用std :: terminate()。
  7. 这怎么可能?

    更新

    我不知道HOW怎么可能,但是Clang 3.3(FreeBSD clang version 3.3(标签/ RELEASE_33 / final 183502)20130610)解决了这个问题。

1 个答案:

答案 0 :(得分:1)

  

这怎么可能?

当抛出异常时,控制传递给__cxa_throw例程(通常在libstdc++.so),然后负责查找catch子句并沿途调用析构函数,std::terminate,则<或调用catch

那么答案很可能是第一个可执行文件(异常工作的那个)使用能够解码库中libstdc++.so的{​​{1}},而第二个应用程序(例外的那个)不起作用),要么使用.eh_frame的较旧(不兼容)版本,要么使用libstdc++.so的链接,或者这些行中的某些内容。

注意:提升异常的实际工作由libstdc++.a中的_Unwind_RaiseException完成,因此即使两个应用程序都使用相同的libgcc_s.so.1,它们也可能仍然使用不同的libstdc++.so

<强>更新

  

我是否可以将libstdc ++和libgcc静态链接到我的.so库中?

也许。 TL; DR:这很复杂。

有几件事需要考虑:

  1. 在i386以外的任何平台上,您必须使用libgcc构建自己的libstdc++.alibgcc.a副本,然后才能将它们链接到-fPIC }。通常这些库是在没有zzz.so的情况下构建的,并且不能静态链接到任何-fPIC

  2. .so静态链接到libstdc++.a 可以将其作为派生作品,并遵守GPL(咨询您的律师)。

    < / LI>
  3. 即使从zzz.so导出_Unwind_RaiseException,通常也会在({之前加载的)zzz.so中定义另一个_Unwind_RaiseException实例,并且早期的实例是将要调用的实例,使您的解决方法无效。要确保调用您的 libgcc_s.so副本,您需要将_Unwind_RaiseExceptionzzz.so相关联,或者使用特殊的链接描述来调用所有调用-Bsymbolic(以及来自_Unwind_RaiseException的所有内容)内部。

  4. 您的解决方法可能会解决libgcc.a的问题,但可能会导致即使以后加载的无关zzz.so出现问题,并且需要系统提供的yyy.so,不是来自_Unwind_RaiseException的那个。这是隐藏所有zzz.so符号并使其成为libgcc.a内部符号的另一个参数。

  5. 所以简短的回答是:这样的解决方法可能会给你带来很大的痛苦。