我需要使用备用glibc
版本,比我系统上安装的版本更新(2.18
vs 2.15
).这里和这里都涉及几个相关的问题
.我在这里问的具体问题如下:
我成立了新的动态连接的库路径(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 <a.c > #include > 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 __libc_start_main@GLIBC_2.2.5 (2) 46: 00000000004005f0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@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
硬编码内部.我可以用new强制运行它ld
,我希望ld
使用new的路径(你可以看到新的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 __libc_start_main@GLIBC_2.2.5 (2) 54: 0000000000400600 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@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
找到libc.so.6
具有不同ABI编号的2个版本时,它ld.so.cache
按照ABI编号下降的顺序放置它们,而不是按照出现的顺序.这可以通过交换它们的位置,重建缓存(with ldconfig
)和列出缓存内容(with ldconfig -p
)来检查.只有当2个libc.so.6
文件具有相同的ABI版本时,它们才会按照外观顺序放入缓存中.
配置glibc
与--enable-kernel=2.6.24
根源它使用相同的ABI版本的系统,而这又修复了问题的提出解决问题,而无需显式的--rpath
或LD_LIBRARY_PATH
.