一个32位版本的应用程序,建立在CentOS 6 x64上,当在较新的Linux上启动时,在"dl_itera
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我的研究表明,如果我在较旧的Linux上构建一个应用程序(及其依赖项(,比如CentOS 6
(带有GLIBC 2.12
(,那么它应该在任何其他具有较新GLIBC
的Linux发行版上都能很好地工作。这个假设是正确的吗?
对不起,这将是一篇很长的帖子,但这不是一个微不足道的问题。
这是构建机器:
$ 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)
应用程序几乎与所有静态链接,因此:
$ 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)
因此:
linux-gate
和ld-linux
并不完全是库,因此它们无法部署libdl
、librt
、libm
、libpthread
和libc
是GLIBC
的一部分,因此不应该同时部署它们(特别是考虑到GNU C库的向后兼容性(libstdc++
和libgcc_s
与二进制文件一起"部署"(取自构建机器(
测试机器:
$ lsb_release -a
Description: Debian GNU/Linux 10 (buster)
$ ldd --version
ldd (Debian GLIBC 2.28-10) 2.28
64位构建(带有libstdc++
和libgcc_s
(似乎运行得非常好。
问题在于32位构建-当抛出异常时(不是所有异常,但似乎是一致的(,它会崩溃。以下是堆栈跟踪的有趣之处:
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
我可以在这里看到两种可能的选择:
- 32位构建有一些问题(尽管它毫无例外地工作(
- 我对这件事确实有很大的误解
有什么想法吗?
我怀疑,如果您将GCC库(g++/GCC(从构建机器"部署"到具有不同操作系统或操作系统版本的目标机器,那么您的应用程序(或其依赖项之一(实际上可以使用目标系统中的GCC库,而其他依赖项则使用您部署的库,从而导致潜在的不兼容。
在目标框上构建应用程序,或者使用交叉编译来精确指定目标框的操作系统和版本,会安全得多。
此外,使用系统库的动态链接更安全,因为否则您可能会在一个应用程序中混合静态和动态库,这可能会导致问题(例如,gcc-lib中某个全局var的两个实例(。
您需要检查整个库依赖关系树,以确保每个库只有一个实例从同一位置加载。例如,您的应用程序依赖于./libgcc_s.so.1
和./libstdc++.so.6
,但./libstdc++.so.6
可能依赖于系统的libgcc_s.so
。
你可以在互联网上搜索这些和其他在非目标框上构建应用程序的陷阱。例如:
因此,仅仅在较旧的发行版上编译应用程序是不够的。
- 无法在 Arch Linux 中启动虚幻引擎 4
- 如何制作启动 Python 脚本的 linux 后台进程(在 c 中)
- 一个32位版本的应用程序,建立在CentOS 6 x64上,当在较新的Linux上启动时,在"dl_itera
- 该命令在QProcess中启动,不会返回Linux上的响应
- 调试从 Linux 中的另一个C++应用程序启动的 python 脚本
- Linux获取通过execl脚本启动的程序的PID
- 使用 gdb 调试 linux 守护程序的初始启动
- C 从内部程序代码上将应用程序添加到Linux程序上的启动中
- 当屏幕保护程序在Linux下启动或停止时,是否可以通知通知
- 通过C 代码在Linux上启动/停止守护程序
- linux通过这个进程启动所有线程
- 从应用程序启动 Linux 服务时避免套接字继承C++
- 如何在 Eclipse 中启动 gdb 调试之前运行 linux 脚本
- 如何以编程方式启动程序并在 Linux 上使用 root 权限运行它
- Linux C++程序通过系统调用启动bash脚本时总是返回-1
- 在Linux上启动时启动我的GTK应用程序
- Linux 系统不允许创建套接字,因为"Too many open files"*即使在重新启动后*
- c++在linux下启动新进程并终止当前进程
- 检测在linux上的另一个线程中的程序启动
- 重新启动linux守护进程