2013-12-13 54 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