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 here và here. 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, cũ 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ũ.