C++例外和 ELF .eh_frame部分

C++ exceptions and the .eh_frame ELF section

本文关键字:frame 部分 eh ELF C++      更新时间:2023-10-16

是.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. zzz.so 中抛出的所有异常都已成功捕获到 zzz.so 中,并转储到我的日志文件中
  4. 还有另一个 aaa.so 加载到另一个二进制文件中。另一个 aaa.so 正在加载我的 zzz.so。
  5. zzz.so 中抛出的所有相同异常都会导致调用 std::terminate((。

这怎么可能?

更新

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

这怎么可能?

引发异常时,控制权传递给__cxa_throw例程(通常为 libstdc++.so (,然后该例程负责查找 catch 子句并在此过程中调用析构函数,或者在找不到catch时调用std::terminate

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

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

更新:

我将 libstdc++ 和 libgcc 静态链接到我的 .so 库中受益吗?

或。DR:这很复杂。

有几件事需要考虑:

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

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

  3. 即使有从zzz.so导出_Unwind_RaiseException,通常已经有另一个在(较早加载的(libgcc_s.so中定义的_Unwind_RaiseException实例,并且该较早的实例是将被调用的实例,从而使您的解决方法无效。为了确保调用_Unwind_RaiseException的副本,您需要将zzz.so-Bsymbolic链接,或者使用特殊的链接器脚本,以便在内部对_Unwind_RaiseException(以及libgcc.a中的所有其他所有内容(进行所有调用。

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

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