C++ ABI、libstdc++

C++ Standard Library: ABI 与 API

  • API: Application Programing Interface,
    The C++ Standard Library has many include files, types defined in those include files, specific named functions, and other behavior. The text of these behaviors, as written in source include files, is called the Application Programing Interface, or API.
  • Complier ABI: Application Binary Interface
    C++ source that is compiled into object files is transformed by the compiler: it arranges objects with specific alignment and in a particular layout, mangling names according to a well-defined algorithm, has specific arrangements for the support of virtual functions, etc. These details are defined as the compiler Application Binary Interface, or ABI. From GCC version 3 onwards the GNU C++ compiler uses an industry-standard C++ ABI, the Itanium C++ ABI.
    mixing C++ ABIs is not recommended at this time

C++标准库的API,与用户机器上所使用的g++编译器的ABI,共同构成了用户机器上的C++标准库的ABI。

GCC/G++中跟ABI有关的库

  • libgcc库
    libgcc库是 “GCC low-level runtime library”,libgcc.a(静态库) or libgcc_s.so(动态库)。该库用来处理:目标处理器无法直接做的数学运算、异常处理以及其他杂项。
    详细内容参考https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html
  • libstdc++库

release versioning 和 symbol versioning

在读GCC的官网文档的时候,https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html, 一直在想里面的release vesioning 和 symbol versioning 到底指的是什么意思呢?现在我的理解是:

  • release versioning指的是发布的版本号,比如 libgcc_s.so.3 或者libstdc++.so.5.0.4这种名字。GCC版本与库的release version有一个mapping关系在官网上列了出来。
  • symbol versioning 是比release versioning更加细粒度的控制,GCC版本与库的symbol version有一个mapping关系也在官网上列了出来,然后通过symbol version直接去gcc的源代码的文件中,就可以找到一个symbol version的新引入了哪些symbol,或者反过来可以找到某个symbol是从哪个symbol version开始引入的。这样你可以更精确的针对某个要用到的symbol找到适配的库版本和GCC版本。在gcc的源代码中,其中libgcc-std.ver文件是ligbcc_s库的symbol versioning记录, libstdc+±v3/config/abi/pre/gnu.ver文件是libstdc++库的symbol versioning记录。

场景

场景1 部署目标机器不在我们的控制范围之内,我们不能升级目标机器的GCC或者库版本,这种情况下需要使用目标机器上面的GLIBCXX版本对应的GCC版本重新编译我们的代码。

参考 https://stackoverflow.com/questions/5216399/usr-lib-libstdc-so-6-version-glibcxx-3-4-15-not-found

  1. 使用如下命令找到目标机器支持的GLIBCXX的最高版本:

    strings /usr/lib/libstdc++.so.6 | grep GLIBC 
    

    如下图所示目标机器支持的最高版本是GLIBCXX_3.4.19.在这里插入图片描述

  2. 在官网 https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html 查找GLIBCXX_版本对应的 GCC 版本,在截图的例子中,GLIBCXX_3.4.19对应的GCC版本是4.8.3.

场景2 运行可执行文件时候出现错误 /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.20’ not found

参考https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_set_paths
这个错误是连接器报的错误,原因是可执行文件是用比较新的GCC编译出来的,但是现在运行时候被连接到了老的libstdc++.so.6库, 其实也就是ABI不匹配了。

场景3

参考https://stackoverflow.com/questions/46746878/is-it-safe-to-link-c17-c14-and-c11-objects 一个高分回答。总结如下:

  • 同一个GCC版本,obj A 用 std=c++11编译,obj B 用std=c++14编译,obj C 用std=c++17编译, 可以正常链接和运行。
  • obj D用GCC 4.9 -std=c++03编译,obj E 用GCC 5 -std=c++11编译,object F 用 GCC 7 -std=c++17编译, 只要链接和运行的时候用GCC 7 或者更新的libstdc++.so版本,也是可以正常连接和运行的。
  • 在第2个例子中,如果再加一个obj G, 使用GCC 8 -std=c++17 编译,并且使用GCC 8 libstdc++.so, 那么F和G链接到一起可能会出问题,因为C++17 support is not stable in GCC 7, 需要把obj F 也用 GCC 8编译才可以。(当然如果GCC 7 对C++17的支持是stable的那就没有任何问题了)

以下是引用SO大神的回答:

For GCC it is safe to link together any combination of objects A, B, and C. If they are all built with the same version then they are ABI compatible, the standard version (i.e. the -std option) doesn’t make any difference.


Why? Because that’s an important property of our implementation which we work hard to ensure.


Where you have problems is if you link together objects compiled with different versions of GCC and you have used unstable features from a new C++ standard before GCC’s support for that standard is complete. For example, if you compile an object using GCC 4.9 and -std=c++11 and another object with GCC 5 and -std=c++11 you will have problems. The C++11 support was experimental in GCC 4.x, and so there were incompatible changes between the GCC 4.9 and 5 versions of C++11 features. Similarly, if you compile one object with GCC 7 and -std=c++17 and another object with GCC 8 and -std=c++17 you will have problems, because C++17 support in GCC 7 and 8 is still experimental and evolving.


On the other hand, any combination of the following objects will work (although see note below about libstdc++.so version):


object D compiled with GCC 4.9 and -std=c++03
object E compiled with GCC 5 and -std=c++11
object F compiled with GCC 7 and -std=c++17
This is because C++03 support is stable in all three compiler versions used, and so the C++03 components are compatible between all the objects. C++11 support is stable since GCC 5, but object D doesn’t use any C++11 features, and objects E and F both use versions where C++11 support is stable. C++17 support is not stable in any of the used compiler versions, but only object F uses C++17 features and so there is no compatibility issue with the other two objects (the only features they share come from C++03 or C++11, and the versions used make those parts OK). If you later wanted to compile a fourth object, G, using GCC 8 and -std=c++17 then you would need to recompile F with the same version (or not link to F) because the C++17 symbols in F and G are incompatible.


The only caveat for the compatibility described above between D, E and F is that your program must use the libstdc++.so shared library from GCC 7 (or later). Because object F was compiled with GCC 7, you need to use the shared library from that release, because compiling any part of the program with GCC 7 might introduce dependencies on symbols that are not present in the libstdc++.so from GCC 4.9 or GCC 5. Similarly, if you linked to object G, built with GCC 8, you would need to use the libstdc++.so from GCC 8 to ensure all symbols needed by G are found. The simple rule is to ensure the shared library the program uses at run-time is at least as new as the version used to compile any of the objects.


Another caveat when using GCC, already mentioned in the comments on your question, is that since GCC 5 there are two implementations of std::string available in libstdc++. The two implementations are not link-compatible (they have different mangled names, so can’t be linked together) but can co-exist in the same binary (they have different mangled names, so don’t conflict if one object uses std::string and the other uses std::__cxx11::string). If your objects use std::string then usually they should all be compiled with the same string implementation. Compile with -D_GLIBCXX_USE_CXX11_ABI=0 to select the original gcc4-compatible implementation, or -D_GLIBCXX_USE_CXX11_ABI=1 to select the new cxx11 implementation (don’t be fooled by the name, it can be used in C++03 too, it’s called cxx11 because it conforms to the C++11 requirements). Which implementation is the default depends on how GCC was configured, but the default can always be overridden at compile-time with the macro.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值