替代glibc动态链接程序的库路径顺序(ld.so)
我需要使用替代glibc
版本,它比我的系统上安装的版本(2.18
vs 2.15
)要新。涉及的几个相关问题 here和here。我问这里的具体问题如下:替代glibc动态链接程序的库路径顺序(ld.so)
我成立了新的动态连接(ld-2.18.so
),使新libc
(libc-2.18.so
)发现前面的老libc
(libc-2.15.so
)的库路径。但是,当我尝试使用新的ld
运行程序时,旧版本libc
被拾取,生成SEGV
。 这是为什么发生?
注:我知道这可以通过在编译时使用--rpath
或在运行时使用LD_LIBRARY_PATH
来解决。不过,我仍然想明白为什么还需要其中之一。
的详细信息如下:
我下载glibc-2.18
并且把它建立在/opt/glibc-2.18
。默认情况下,文件/opt/glibc-2.18/etc/ld.so.conf
缺失。我创建了它,并更新了新的glibc
的库缓存,如下所示。我强调的是:新libc
是以前的老libc
发现:
$ cat /opt/glibc-2.18/etc/ld.so.conf
/opt/glibc-2.18/lib
/usr/local/lib
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/mesa
/lib
/usr/lib
$ /opt/glibc-2.18/sbin/ldconfig -v |& grep -E '^[^'$'\t'']|libc\.'
/opt/glibc-2.18/sbin/ldconfig: Path `/opt/glibc-2.18/lib' given more than once
/opt/glibc-2.18/sbin/ldconfig: Can't stat /opt/glibc-2.18/lib64: No such file or directory
/opt/glibc-2.18/sbin/ldconfig: Can't stat /opt/glibc-2.18/libx32: No such file or directory
/opt/glibc-2.18/lib:
libc.so.6 -> libc-2.18.so
/usr/local/lib:
/lib/x86_64-linux-gnu:
libc.so.6 -> libc-2.15.so
/usr/lib/x86_64-linux-gnu:
/usr/lib/x86_64-linux-gnu/mesa:
/lib:
/usr/lib:
然后,我创建了一个简单的C程序:
$ cat <<EOF >a.c
> #include <stdio.h>
> int main()
> {
> fprintf(stdout, "ok\n");
> return 0;
> }
> EOF
$ g++ a.c
$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x43b8484e3910072375d68418cb6327478266c0e9, not stripped
$ ldd a.out
linux-vdso.so.1 => (0x00007fffd7ffe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa7c47bd000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa7c4b9b000)
$ readelf -a a.out | grep lib
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
000000601000 000100000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
46: 00000000004005f0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_
57: 0000000000400560 137 FUNC GLOBAL DEFAULT 13 __libc_csu_init
000000: Version: 1 File: libc.so.6 Cnt: 1
$ objdump -x a.out | grep -A3 Version
Version References:
required from libc.so.6:
0x09691a75 0x00 02 GLIBC_2.2.5
由上述可见,这一计划有老人ld
硬在里面编码。我可以用新的ld
强制运行它,我期望使用新的ld
的路径(你可以看到新的ld.so.cache
被打开)。然而,由于某种原因,我想明白了,老libc
之前新libc
发现,产生SEGV:
$ /opt/glibc-2.18/lib/ld-2.18.so ./a.out
Segmentation fault (core dumped)
$ strace /opt/glibc-2.18/lib/ld-2.18.so ./a.out |& grep open
open("./a.out", O_RDONLY|O_CLOEXEC) = 3
open("/opt/glibc-2.18/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
我也可以编译新的库和烘烤新ld
如下:
$ g++ -L/opt/glibc-2.18/lib -Wl,--dynamic-linker=/opt/glibc-2.18/lib/ld-2.18.so a.c -o a.2.18.out
$ file a.2.18.out
a.2.18.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x25ab43f3d29b49fa21385a15e43325e9fb904e81, not stripped
$ ldd a.2.18.out
linux-vdso.so.1 => (0x00007fffa68da000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9df5cbe000)
/opt/glibc-2.18/lib/ld-2.18.so => /lib64/ld-linux-x86-64.so.2 (0x00007f9df609c000)
$ readelf -a a.2.18.out | grep lib
[Requesting program interpreter: /opt/glibc-2.18/lib/ld-2.18.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
000000601000 000100000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
54: 0000000000400600 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_
65: 0000000000400570 137 FUNC GLOBAL DEFAULT 13 __libc_csu_init
000000: Version: 1 File: libc.so.6 Cnt: 1
$ objdump -x a.2.18.out | grep -A3 Version
Version References:
required from libc.so.6:
0x09691a75 0x00 02 GLIBC_2.2.5
不过,如果我尝试运行新程序的同样的事情发生,旧的libc
正在使用的新libc
代替:
$ ./a.2.18.out
Segmentation fault (core dumped)
$ strace ./a.2.18.out |& grep open
open("/opt/glibc-2.18/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
使用任一可执行文件,指定LD_LIBRARY_PATH=/opt/glibc-2.18/lib
使它工作。然而,我的问题是为什么仍然需要,因为新的ld
的路径在开始时配置为在旧的libc
之前提取新的libc
。
我明白了,问题出在OS ABI版本上。那是,如file
指示的号码:
$ file /lib/x86_64-linux-gnu/libc-2.15.so | grep -o "for GNU/Linux [0-9.]*"
for GNU/Linux 2.6.24
当glibc
配置了无非--prefix
另一方面,它建立在默认情况下使用ABI版本小(!!)(在我的情况下,2.6.16
)比系统上的默认值(2.6.24
)。所以libc-2.18
的ABI版本小于libc-2.15
。
当ldconfig
发现不同的ABI数字2个版本的libc.so.6
,它在外观上没有的顺序将它们放置在ld.so.cache
降序ABI数的顺序。这可以通过交换位置,重建缓存(使用ldconfig
)并列出缓存内容(使用ldconfig -p
)来检查。只有当2 libc.so.6
文件具有相同的ABI版本时,才按照外观顺序将它们放入缓存中。
配置glibc
与--enable-kernel=2.6.24
导致它使用相同的ABI版本的系统,而这又修复了问题的提出解决问题,而不需要明确的--rpath
或LD_LIBRARY_PATH
。