提问者:小点点

与ABI::CXX11的符号连接问题?


我们最近抓到一个报告,因为GCC5.1,libstdc++和双ABI。 Clang似乎没有意识到GCC内联名称空间的更改,因此它基于一组名称空间或符号生成代码,而GCC使用另一组名称空间或符号。 在链接时,由于缺少符号而出现问题。

如果我正确地解析了双ABI页面,那么它看起来就像是在_glibcxx_use_cxx11_abiABI::cxx11上进行旋转一样,还需要一些额外的困难。 更多的阅读可以在Red Hat的博客上找到,GCC5和C++11 ABI,以及GCC-5.1和两个C++ABI的案例。

下面是一台Ubuntu15机器。 机器提供GCC 5.2.1。

$ cat test.cxx
#include <string>

std::string foo __attribute__ ((visibility ("default")));
std::string bar __attribute__ ((visibility ("default")));

$ g++ -g3 -O2 -shared test.cxx -o test.so

$ nm test.so | grep _Z3
...
0000201c B _Z3barB5cxx11
00002034 B _Z3fooB5cxx11

$ echo _Z3fooB5cxx11 _Z3barB5cxx11 | c++filt 
foo[abi:cxx11] bar[abi:cxx11]

如何生成一个带有符号的二进制文件,该二进制文件同时使用两种装饰(红帽博客称之为“共存”)?

或者,我们有什么选择?

我正在努力为用户实现一个“它只是工作”。 我不关心是否存在两个具有两种不同行为的弱符号(std::string缺少写时复制,而std::string[abi:cxx11]提供写时复制)。 或者,一个可以是另一个的别名。

Debian在Debian Bug报告日志中有大量类似的Bug:标记为libstdc++-cxx11的Bug。 他们的解决方案是在新的ABI下重建所有的东西,但是它没有处理混合/匹配编译器的角情况,模ABI的变化。

在苹果的世界里,我认为这接近于一个胖的二进制。 但是我不确定在Linux/GCC世界中该做什么。 最后,我们不能控制发行版如何构建库,也不能控制使用什么编译器将应用程序与库链接起来。


共2个答案

匿名用户

免责声明,以下内容未经生产测试,使用风险自负。

你可以自己在双ABI下释放你的库。 这或多或少类似于OSX的“fat binary”,但完全是用C++构建的。

最简单的方法是编译库两次:-D_glibcxx_use_cxx11_abi=0-D_glibcxx_use_cxx11_abi=1。 根据宏的值,将整个库置于两个不同的命名空间下:

#if _GLIBCXX_USE_CXX11_ABI
#  define DUAL_ABI cxx11 __attribute__((abi_tag("cxx11")))
#else
#  define DUAL_ABI cxx03
#endif

namespace CryptoPP {
  inline namespace DUAL_ABI {
    // library goes here
  }
}

现在您的用户可以像往常一样使用cryptopp::whatever,这将映射到cryptopp::CXX11::whatevercryptopp::CXX03::whatever,具体取决于所选的ABI。

注意,GCC手册说,这个方法将更改标记内联命名空间中定义的所有东西的损坏名称。 根据我的经验,这种情况不会发生。

另一种方法是,如果_glibcxx_use_cxx11_abi为非零,则用__attribute__((abi_tag("cxx11“)))标记每个类,函数和变量。 这个属性很好地将[cxx11]添加到去钓鱼器的输出中。 我认为使用名称空间同样有效,并且需要对现有代码进行更少的修改。

理论上,您不需要复制整个库,只需要复制使用std::stringstd::list的函数和类,以及使用这些函数和类的函数和类,等等递归。 但在实践中,它可能不值得这么做,特别是如果库不是很大的话。

匿名用户

这里有一种方法,但它不是很优雅。 我也不清楚如何使GCC自动化它,这样我就不必做两次事情。

首先,要变成库的例子:

$ cat test.cxx
#include <string>

std::string foo __attribute__ ((visibility ("default")));
std::string bar __attribute__ ((visibility ("default")));

那么:

$ g++ -D_GLIBCXX_USE_CXX11_ABI=0 -c test.cxx -o test-v1.o
$ g++ -D_GLIBCXX_USE_CXX11_ABI=1 -c test.cxx -o test-v2.o

$ ar cr test.a test-v1.o test-v2.o
$ ranlib test.a

$ g++ -shared test-v1.o test-v2.o -o test.so

最后,看看我们得到了什么:

$ nm test.a

test-v1.o:
00000004 B bar
         U __cxa_atexit
         U __dso_handle
00000000 B foo
0000006c t _GLOBAL__sub_I_foo
00000000 t _Z41__static_initialization_and_destruction_0ii
         U _ZNSsC1Ev
         U _ZNSsD1Ev

test-v2.o:
         U __cxa_atexit
         U __dso_handle
0000006c t _GLOBAL__sub_I__Z3fooB5cxx11
00000018 B _Z3barB5cxx11
00000000 B _Z3fooB5cxx11
00000000 t _Z41__static_initialization_and_destruction_0ii
         U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev
         U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev

和:

$ nm test.so

00002020 B bar
00002018 B __bss_start
00002018 b completed.7181
         U __cxa_atexit@@GLIBC_2.1.3
         w __cxa_finalize@@GLIBC_2.1.3
00000650 t deregister_tm_clones
000006e0 t __do_global_dtors_aux
00001ef4 t __do_global_dtors_aux_fini_array_entry
00002014 d __dso_handle
00001efc d _DYNAMIC
00002018 D _edata
00002054 B _end
0000087c T _fini
0000201c B foo
00000730 t frame_dummy
00001ee8 t __frame_dummy_init_array_entry
00000980 r __FRAME_END__
00002000 d _GLOBAL_OFFSET_TABLE_
000007dc t _GLOBAL__sub_I_foo
00000862 t _GLOBAL__sub_I__Z3fooB5cxx11
         w __gmon_start__
000005e0 T _init
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
00001ef8 d __JCR_END__
00001ef8 d __JCR_LIST__
         w _Jv_RegisterClasses
00000690 t register_tm_clones
00002018 d __TMC_END__
00000640 t __x86.get_pc_thunk.bx
0000076c t __x86.get_pc_thunk.dx
0000203c B _Z3barB5cxx11
00002024 B _Z3fooB5cxx11
00000770 t _Z41__static_initialization_and_destruction_0ii
000007f6 t _Z41__static_initialization_and_destruction_0ii
         U _ZNSsC1Ev@@GLIBCXX_3.4
         U _ZNSsD1Ev@@GLIBCXX_3.4
         U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev@@GLIBCXX_3.4.21
         U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev@@GLIBCXX_3.4.21