2013-12-13 18 views
7

Tôi cần sử dụng phiên bản glibc thay thế, mới hơn phiên bản được cài đặt trên hệ thống của tôi (2.18 vs 2.15). Một số vấn đề liên quan được đề cập đến herehere. Các câu hỏi cụ thể tôi đang hỏi ở đây như sau:Thứ tự đường dẫn thư viện cho liên kết động glibc thay thế (ld.so)

tôi thiết lập các đường dẫn thư viện của mối liên kết mới năng động (ld-2.18.so) để các mới libc (libc-2.18.so) được tìm thấy trước cái cũ libc (libc-2.15.so). Tuy nhiên, khi tôi cố gắng chạy một chương trình với ld mới, phiên bản cũ của libc được chọn, tạo ra một SEGV. Tại sao điều đó lại xảy ra?

Lưu ý: Tôi biết điều này có thể được khắc phục bằng cách sử dụng --rpath lúc biên dịch hoặc LD_LIBRARY_PATH vào thời gian chạy. Tuy nhiên, tôi vẫn muốn hiểu tại sao một trong những điều này vẫn còn cần thiết.

Các chi tiết theo:

tôi tải glibc-2.18 và xây dựng nó ở /opt/glibc-2.18. Theo mặc định, tệp thiếu /opt/glibc-2.18/etc/ld.so.conf. Tôi đã tạo nó và cập nhật bộ nhớ cache của thư viện của glibc mới như sau. Tôi nhấn mạnh rằng: mới libc được tìm thấy trước cái cũ 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: 

Sau đó, tôi đã tạo ra một chương trình C đơn giản:

$ 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 

Như đã thấy ở trên, chương trình này có tuổi ld cứng -có mã bên trong. Tôi có thể chạy nó một cách mạnh mẽ với ld mới và tôi hy vọng đường dẫn của ld mới sẽ được sử dụng (bạn có thể thấy ld.so.cache mới đang được mở). Tuy nhiên, đối với một số lý do tôi đang cố gắng để hiểu, libc được tìm thấy trước mới libc, tạo ra một 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 

Tôi cũng có thể biên dịch với thư viện mới và nướng-in mới ld như sau:

$ 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 

Tuy nhiên, nếu tôi cố gắng để chạy các chương trình mới điều tương tự xảy ra, người già libc đang được sử dụng thay cho mới 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 

Có thể thực thi, chỉ định LD_LIBRARY_PATH=/opt/glibc-2.18/lib làm cho nó hoạt động. Tuy nhiên, câu hỏi của tôi ở đây là lý do tại sao vẫn cần thiết, vì đường dẫn của ld mới được cấu hình ngay từ đầu để đón libc mới trước số libc cũ.

Trả lời

5

Tôi hiểu rồi, sự cố xảy ra với phiên bản OSI OSI. Đó là số lượng chỉ định bởi file, chẳng hạn như:

$ file /lib/x86_64-linux-gnu/libc-2.15.so | grep -o "for GNU/Linux [0-9.]*" 
for GNU/Linux 2.6.24 

Khi glibc được cấu hình không có gì khác hơn là --prefix, nó được xây dựng theo mặc định với một phiên bản ABI nhỏ hơn (!!) (trong trường hợp của tôi, 2.6.16) so với mặc định trên hệ thống (2.6.24). Vì vậy, libc-2.18 có phiên bản ABI nhỏ hơn libc-2.15.

Khi ldconfig thấy 2 phiên bản của libc.so.6 với số ABI khác nhau, nó đặt họ vào ld.so.cachetheo thứ tự giảm dần số ABI, không theo thứ tự xuất hiện. Điều này có thể được kiểm tra bằng cách hoán đổi vị trí của họ, xây dựng lại bộ nhớ đệm (với ldconfig) và liệt kê nội dung bộ nhớ cache (với ldconfig -p). Chỉ khi 2 libc.so.6 tệp có cùng phiên bản ABI, chúng có được đặt trong bộ nhớ cache theo thứ tự xuất hiện không.

Cấu hình glibc với --enable-kernel=2.6.24 gây ra nó để sử dụng cùng một phiên bản ABI như hệ thống, do đó sửa chữa các vấn đề độ phân giải trong báo cáo kết quả câu hỏi, mà không cần đến một rõ ràng --rpath hoặc LD_LIBRARY_PATH.

Các vấn đề liên quan