【问题标题】:C++ exceptions and the .eh_frame ELF sectionC++ 异常和 .eh_frame ELF 部分
【发布时间】:2015-10-09 09:47:22
【问题描述】:

.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 version 3.3 (tags/RELEASE_33/final 183502) 20130610)解决了这个问题。

【问题讨论】:

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


    【解决方案1】:

    这怎么可能?

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

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

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

    更新:

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

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

    有几点需要考虑:

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

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

    3. 1234563被调用,使您的解决方法无效。为确保调用_Unwind_RaiseException 的您的 副本,您需要将zzz.so 与-Bsymbolic 链接,或使用特殊的链接器脚本来调用_Unwind_RaiseException(以及所有否则来自libgcc.a) 内部。 1234563 @。这是隐藏所有libgcc.a 符号并使它们成为zzz.so 内部的另一个论点。

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

    【讨论】:

    • 我会从静态链接 libstdc++ 和 libgcc 到我的 .so 库中受益吗?
    • “__cxa_throw” 只是“_Unwind_RaiseException”的包装吗?
    • @pavelkolodin 是的,对于“只是一个包装器”的一些定义。如果这就是您的意思,它不仅会调用_Unwind_RaiseException。它的来源在这里:github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/…
    • 如果我将 -std=c++11 添加到编译器 g++47,我的 .so 异常将停止工作。但是 ldd 对最终 .so 的两个版本的输出是相同的。没有 -std=c++11 一切正常。
    • 我还注意到 -std=c++11 .so 二进制文件没有“.tdata”部分,如果我删除 -std=c++11 编译器选项,则会出现该部分。
    猜你喜欢
    • 1970-01-01
    • 2014-02-16
    • 2012-12-15
    • 2011-12-27
    • 2014-12-05
    • 2018-10-23
    • 2012-12-01
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多