2013-12-13 185 views
7

我需要使用替代glibc版本,它比我的系统上安装的版本(2.18 vs 2.15)要新。涉及的几个相关问题 herehere。我问这里的具体问题如下:替代glibc动态链接程序的库路径顺序(ld.so)

我成立了新的动态连接(ld-2.18.so),使新libclibc-2.18.so)发现前面的老libclibc-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

回答

5

我明白了,问题出在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版本的系统,而这又修复了问题的提出解决问题,而不需要明确的--rpathLD_LIBRARY_PATH