C++ 异常和 .eh_frame ELF 部分
C++ exceptions and the .eh_frame ELF section
是否是 .eh_frame ELF 部分的缺失或损坏导致我的 C++ 代码中的异常停止工作?之前成功捕获的任何异常现在都在调用 std::terminate()。
我的情况:
我的 zzz.so 共享库有 try-catch 块:
try {
throw Exc();
} catch (const Exc &e) {
LOG("ok " << e.what());
} catch (...) {
LOG("all");
}
加载 zzz.so 的可执行文件(使用 ldopen)。它调用 zzz.so
中的一个函数
- zzz.so 中抛出的所有异常都在 zzz.so 中成功捕获并转储到我的日志文件中
- 还有一个 aaa.so 被加载到另一个二进制文件中。另一个 aaa.so 正在加载我的 zzz.so.
- 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_frame
的 libstdc++.so
,而第二个应用程序(那个异常不起作用),要么使用较旧(不兼容)的 libstdc++.so
版本,要么使用 links 反对 libstdc++.a
,或者类似的东西。
注意:实际引发异常的工作是由_Unwind_RaiseException
在libgcc_s.so.1
中完成的,所以即使两个应用程序使用相同的[=11] =], 他们可能仍然使用不同的 libgcc
.
更新:
Will I benefit from static linking libstdc++ and libgcc into my .so library?
也许吧。 TL;DR:这很复杂。
有几点需要考虑:
在除 i386 以外的任何平台上,您必须先使用 -fPIC
构建自己的 libstdc++.a
和 libgcc.a
副本,然后才能 link 他们进入你的 zzz.so
。通常这些库是在没有 -fPIC
的情况下构建的,并且不能静态 linked 到任何 .so
.
将 libstdc++.a
静态 linking 到您的 zzz.so
可能 使其成为衍生作品,并受GPL(咨询您的律师)。
即使从 zzz.so
导出了 _Unwind_RaiseException
,通常已经有另一个 _Unwind_RaiseException
的实例定义在(较早加载的)libgcc_s.so
,而较早的实例将被调用,从而使您的解决方法无效。为确保调用 _Unwind_RaiseException
的 您的 副本,您需要 link zzz.so
和 -Bsymbolic
,或使用特殊的linker 脚本使对 _Unwind_RaiseException
的所有调用(以及来自 libgcc.a
的所有其他内容)都在内部。
您的变通方法可能会解决 zzz.so
的问题,但可能会导致不相关的 yyy.so
出现问题,后者加载得更晚,需要系统提供的 _Unwind_RaiseException
,而不是 zzz.so
中的那个。这是隐藏所有 libgcc.a
符号并将它们置于 zzz.so
.
内部的另一个论点
所以简短的回答是:这种变通办法可能会给您带来很多痛苦。
是否是 .eh_frame ELF 部分的缺失或损坏导致我的 C++ 代码中的异常停止工作?之前成功捕获的任何异常现在都在调用 std::terminate()。
我的情况:
我的 zzz.so 共享库有 try-catch 块:
try { throw Exc(); } catch (const Exc &e) { LOG("ok " << e.what()); } catch (...) { LOG("all"); }
加载 zzz.so 的可执行文件(使用 ldopen)。它调用 zzz.so
中的一个函数
- zzz.so 中抛出的所有异常都在 zzz.so 中成功捕获并转储到我的日志文件中
- 还有一个 aaa.so 被加载到另一个二进制文件中。另一个 aaa.so 正在加载我的 zzz.so.
- 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_frame
的 libstdc++.so
,而第二个应用程序(那个异常不起作用),要么使用较旧(不兼容)的 libstdc++.so
版本,要么使用 links 反对 libstdc++.a
,或者类似的东西。
注意:实际引发异常的工作是由_Unwind_RaiseException
在libgcc_s.so.1
中完成的,所以即使两个应用程序使用相同的[=11] =], 他们可能仍然使用不同的 libgcc
.
更新:
Will I benefit from static linking libstdc++ and libgcc into my .so library?
也许吧。 TL;DR:这很复杂。
有几点需要考虑:
在除 i386 以外的任何平台上,您必须先使用
-fPIC
构建自己的libstdc++.a
和libgcc.a
副本,然后才能 link 他们进入你的zzz.so
。通常这些库是在没有-fPIC
的情况下构建的,并且不能静态 linked 到任何.so
.将
libstdc++.a
静态 linking 到您的zzz.so
可能 使其成为衍生作品,并受GPL(咨询您的律师)。即使从
zzz.so
导出了_Unwind_RaiseException
,通常已经有另一个_Unwind_RaiseException
的实例定义在(较早加载的)libgcc_s.so
,而较早的实例将被调用,从而使您的解决方法无效。为确保调用_Unwind_RaiseException
的 您的 副本,您需要 linkzzz.so
和-Bsymbolic
,或使用特殊的linker 脚本使对_Unwind_RaiseException
的所有调用(以及来自libgcc.a
的所有其他内容)都在内部。您的变通方法可能会解决
zzz.so
的问题,但可能会导致不相关的yyy.so
出现问题,后者加载得更晚,需要系统提供的_Unwind_RaiseException
,而不是zzz.so
中的那个。这是隐藏所有libgcc.a
符号并将它们置于zzz.so
. 内部的另一个论点
所以简短的回答是:这种变通办法可能会给您带来很多痛苦。