C++ 异常和 .eh_frame ELF 部分

C++ exceptions and the .eh_frame ELF section

是否是 .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()。

这怎么可能?

更新

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

How is that possible?

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

那么答案很可能是第一个可执行文件(异常有效的那个)使用能够在你的库中解码 .eh_framelibstdc++.so,而第二个应用程序(那个异常不起作用),要么使用较旧(不兼容)的 libstdc++.so 版本,要么使用 links 反对 libstdc++.a,或者类似的东西。

注意:实际引发异常的工作是由_Unwind_RaiseExceptionlibgcc_s.so.1中完成的,所以即使两个应用程序使用相同的[=11] =], 他们可能仍然使用不同的 libgcc.

更新:

Will I benefit from static linking libstdc++ and libgcc into my .so library?

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

有几点需要考虑:

  1. 在除 i386 以外的任何平台上,您必须先使用 -fPIC 构建自己的 libstdc++.alibgcc.a 副本,然后才能 link 他们进入你的 zzz.so。通常这些库是在没有 -fPIC 的情况下构建的,并且不能静态 linked 到任何 .so.

  2. libstdc++.a 静态 linking 到您的 zzz.so 可能 使其成为衍生作品,并受GPL(咨询您的律师)。

  3. 即使从 zzz.so 导出了 _Unwind_RaiseException,通常已经有另一个 _Unwind_RaiseException 的实例定义在(较早加载的)libgcc_s.so,而较早的实例将被调用,从而使您的解决方法无效。为确保调用 _Unwind_RaiseException 您的 副本,您需要 link zzz.so-Bsymbolic,或使用特殊的linker 脚本使对 _Unwind_RaiseException 的所有调用(以及来自 libgcc.a 的所有其他内容)都在内部。

  4. 您的变通方法可能会解决 zzz.so 的问题,但可能会导致不相关的 yyy.so 出现问题,后者加载得更晚,需要系统提供的 _Unwind_RaiseException,而不是 zzz.so 中的那个。这是隐藏所有 libgcc.a 符号并将它们置于 zzz.so.

  5. 内部的另一个论点

所以简短的回答是:这种变通办法可能会给您带来很多痛苦。