简体   繁体   English

基于 CentOS 6 x64 构建的 32 位版本的应用程序在 `dl_iterate_phdr` 中的异常期间崩溃,当在较新的 Linux 上启动时

[英]A 32bit version of an application, built on CentOS 6 x64, crashes during exceptions in `dl_iterate_phdr`, when started on newer Linux

TL;DR; TL;博士; My research shows that if I build an application (and its dependencies) on older Linux like CentOS 6 (with GLIBC 2.12 ), it is supposed to work perfectly fine on any other Linux distro, which has newer GLIBC .我的研究表明,如果我在较旧的 Linux 上构建应用程序(及其依赖项),例如CentOS 6 (带有GLIBC 2.12 ),它应该可以在任何其他具有新GLIBC 2.12 的 ZEDC9F0A5A5D57797BF6.BC 发行版、 Isn't this assumption correct?这个假设不正确吗?


Sorry, it's gonna be a long post, but it's not a trivial question.对不起,这将是一个很长的帖子,但这不是一个微不足道的问题。

Here's the build machine:这是构建机器:

$ rpm -q centos-release
  centos-release-6-10.el6.centos.12.3.x86_64
$ ldd --version
  ldd (GNU libc) 2.12
$ ld -v
  GNU ld version 2.30-54.el6
$ gcc --version
  gcc (GCC) 8.3.1 20190311 (Red Hat 8.3.1-3)
$ g++ --version
  g++ (GCC) 8.3.1 20190311 (Red Hat 8.3.1-3)

The application links with almost everything statically, so:应用程序与几乎所有内容都静态链接,因此:

$ ldd ./app 
linux-gate.so.1 (0xf7f73000)
libdl.so.2 => /lib32/libdl.so.2 (0xf7f4c000)
librt.so.1 => /lib32/librt.so.1 (0xf7f41000)
libstdc++.so.6 => ./libstdc++.so.6 (0xf7e22000)
libm.so.6 => /lib32/libm.so.6 (0xf7d53000)
libgcc_s.so.1 => ./libgcc_s.so.1 (0xf7d35000)
libpthread.so.0 => /lib32/libpthread.so.0 (0xf7d14000)
libc.so.6 => /lib32/libc.so.6 (0xf7b36000)
/lib/ld-linux.so.2 (0xf7f75000)

So:所以:

  • linux-gate and ld-linux aren't exactly libs, so they can't be deployed; linux-gateld-linux不完全是库,所以它们不能被部署;
  • libdl , librt , libm , libpthread and libc are a part of the GLIBC , so they shouldn't be deployed as well (especially given the backward compatibility of the GNU C library); libdllibrtlibmlibpthreadlibcGLIBC的一部分,因此也不应该部署它们(特别是考虑到 GNU C 库的向后兼容性);
  • libstdc++ and libgcc_s are "deployed" together with the binary (taken from the build machine) libstdc++libgcc_s与二进制文件一起“部署”(取自构建机器)

The test machine:试验机:

$ lsb_release -a
  Description:  Debian GNU/Linux 10 (buster)
$ ldd --version
  ldd (Debian GLIBC 2.28-10) 2.28

The 64bit build (with its libstdc++ and libgcc_s ) seems to work perfectly fine. 64 位构建(及其libstdc++libgcc_s )似乎工作得很好。

The issue is with the 32bit build - it crashes , when an exception is thrown (not for all exceptions, but seems to be consistent).问题在于 32 位构建 - 它会在引发异常时崩溃(并非针对所有异常,但似乎是一致的)。 Here's how interesting the stack trace is:以下是堆栈跟踪的有趣之处:

 SIGSEGV at  0# __kernel_sigreturn in linux-gate.so.1
 1# dl_iterate_phdr in /lib32/libc.so.6
 2# _Unwind_Find_FDE in ./libgcc_s.so.1
 3# 0xF7D88AAE in ./libgcc_s.so.1
 4# 0xF7D89227 in ./libgcc_s.so.1
 5# _Unwind_RaiseException in ./libgcc_s.so.1
 6# __cxa_throw in ./libstdc++.so.6
 7# <some funct> in ./app
 7# <some funct> in ./app
 7# <some funct> in ./app
 7# <some funct> in ./app
 7# <some funct> in ./app
 7# <some funct> in ./app
13# make_fcontext in ./app

I can see two possible options here:我可以在这里看到两个可能的选项:

  1. there's something broken with the 32bit build (although it works without exceptions); 32 位版本有一些问题(尽管它可以正常工作);
  2. I do have some big misunderstanding on the matter.我对这件事确实有一些很大的误解。

Any ideas?有任何想法吗?

I suspect that if you "deploy" GCC libs (g++/gcc) from build machine to target one with different OS or OS version, then your app (or one of its dependencies) can actually use GCC libs from the target system, and other dependencies use libs that you deployed, leading to potential incompatibilities.我怀疑如果您从构建机器“部署” GCC 库(g++/gcc)到具有不同操作系统或操作系统版本的目标,那么您的应用程序(或其依赖项之一)实际上可以使用来自目标系统的 GCC 库和其他依赖项使用您部署的库,从而导致潜在的不兼容性。

It's much safer to build your application on target box, or use cross-compilation specifying exactly target box OS and version.在目标框上构建应用程序或使用交叉编译来准确指定目标框操作系统和版本要安全得多。

Also it's safer to use dynamic linking with system libs because otherwise you may end up with the situation of mixing static and dynamic lib in one app, and this may lead to problems (eg two instances of some global var in gcc lib).此外,将动态链接与系统库一起使用更安全,否则您最终可能会遇到在一个应用程序中混合 static 和动态库的情况,这可能会导致问题(例如 gcc 库中的某些全局变量的两个实例)。

You'll need to check whole tree of lib dependencies to ensure that only one instance of every lib is loaded from the same location.您需要检查整个库依赖关系树,以确保每个库只有一个实例从同一位置加载。 For example your app depends on ./libgcc_s.so.1 and ./libstdc++.so.6 but ./libstdc++.so.6 may depend on system's libgcc_s.so .例如,您的应用程序依赖于./libgcc_s.so.1./libstdc++.so.6./libstdc++.so.6可能依赖于系统的libgcc_s.so

You may search on Internet about these and other pitfalls with building your app on non-target box.您可以在 Internet 上搜索有关在非目标框上构建应用程序的这些和其他陷阱。 Eg here :例如 这里

So just compiling your application on an older distribution is not enough.因此,仅在较旧的发行版上编译您的应用程序是不够的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM