C ++异常和.eh_frame ELF部分 [英] C++ exceptions and the .eh_frame ELF section

查看:664
本文介绍了C ++异常和.eh_frame ELF部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我的情况:



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

      $ b 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()。

  • 如何实现?



    更新
    $ b

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

    解决方案


    如何实现?


    当抛出异常时,控制传递到 __ cxa_throw 例程(通常在 libstdc ++中,因此),负责找到 catch 子句,然后调用析构函数调用 std :: terminate 如果没有发现 catch



    答案很可能是第一个可执行文件异常工作)使用 libstdc ++,因此能够解码库中的 .eh_frame ,而第二个应用程序一个其中异常不工作),使用 libstdc ++的旧版本(不兼容)。,或者链接 libstdc ++。a ,或沿着这些行。



    注意:实际提高异常的工作由 _Unwind_RaiseException libgcc_s.so.1 ,所以即使两个应用程序使用相同的 libstdc ++。 c>,他们可能仍然使用不同的 libgcc



    更新: >


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


    也许。



      $ b li>

      在任何i386平台之外的平台上,您必须自己创建 libstdc ++的副本。 libgcc.a -fPIC ,然后才能将它们链接到 zzz.so 。通常,这些库不包含 -fPIC ,并且不能静态链接到任何 .so


    1. libstdc ++,a 静态链接到 zzz.so


    2. 即使有

      zzz.so 导出的code> _Unwind_RaiseException
      ,通常已经有 _Unwind_RaiseException 在(载入早期) libgcc_s.so 中定义,并且早期实例是将被调用的实例,使您的解决方法无效。要确保 _Unwind_RaiseException 的副本被调用,您需要链接 zzz.so -Bsymbolic ,或使用一个特殊的链接器脚本,使所有调用 _Unwind_RaiseException code> libgcc.a


    3. 您的解决方法可能会解决 zzz .so ,但可能会导致一个问题,无关的 yyy.so 即使以后加载,并且希望系统提供 _Unwind_RaiseException ,而不是 zzz.so 中的一个。这是隐藏所有 libgcc.a 符号并使它们在 zzz.so 内部的另一个参数。


    所以简单的答案是:这种解决方法有点可能会让你很痛苦。


    Is it that the absence or damage of the .eh_frame ELF section is the cause of exceptions in my C++ code stopped working? Any exception that previously was caught successfully is now calling std::terminate().

    My situation:

    1. My zzz.so shared library has try-catch blocks:

      try {
          throw Exc();
      } catch (const Exc &e) {
          LOG("ok " << e.what());
      } catch (...) {
          LOG("all");
      }
      

    2. An executable which loads the zzz.so (using ldopen). It call a function in the zzz.so

    3. All the exceptions thrown in the zzz.so are successfully caught inside zzz.so and dumped into my log file
    4. There is another aaa.so that is loaded into another binary. That another aaa.so is loading my zzz.so.
    5. All the same exceptions thrown in the zzz.so lead to call std::terminate().

    How is that possible?

    update

    I don't know HOW is that possible still, but Clang 3.3 (FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610) solved the problem.

    解决方案

    How is that possible?

    When an exception is thrown, control passes to __cxa_throw routine (usually in libstdc++.so), which is then responsible for finding the catch clause and calling destructors along the way, or calling std::terminate if no catch is found.

    The answer then is most likely that the first executable (the one where exceptions work) uses libstdc++.so that is capable of decoding .eh_frame in your library, while the second application (the one where exceptions do not work), either uses an older (incompatible) version of libstdc++.so, or links against libstdc++.a, or something along these lines.

    Note: the actual work of raising the exception is done by _Unwind_RaiseException in libgcc_s.so.1, so even if both applications use the same libstdc++.so, they may still use different libgcc.

    Update:

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

    Maybe. TL;DR: it's complicated.

    There are a few things to consider:

    1. On any platform other than i386, you would have to build your own copy of libstdc++.a and libgcc.a with -fPIC before you can link them into your zzz.so. Normally these libraries are built without -fPIC, and can't be statically linked into any .so.

    2. Static linking of libstdc++.a into your zzz.so may make it a derived work, and subject to GPL (consult your lawyer).

    3. Even when there is a _Unwind_RaiseException exported from zzz.so, normally there will already be another instance of _Unwind_RaiseException defined in (loaded earlier) libgcc_s.so, and that earlier instance is the one that will be called, rendering your workaround ineffective. To make sure that your copy of _Unwind_RaiseException is called, you would need to link zzz.so with -Bsymbolic, or with a special linker script to make all calls to _Unwind_RaiseException (and everything else from libgcc.a) internal.

    4. Your workaround may fix the problem for zzz.so, but may cause a problem for unrelated yyy.so that is loaded even later, and that wants the system-provided _Unwind_RaiseException, not the one from zzz.so. This is another argument for hiding all libgcc.a symbols and making them internal to zzz.so.

    So the short answer is: such workaround is somewhat likely to cause you a lot of pain.

    这篇关于C ++异常和.eh_frame ELF部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆