【解惑】由动态库名引发的血案

本帖最后由 勤奋的小青蛙 于 2017-10-6 12:52 编辑 有时候会遇到这种问题,我在编译时指定了动态库 -labc,编译也通过了。然后把应用程序和这些库文件libabc.so libabc.so.0.0.1 放到开发板上,但是运行时却报错找不到 libabc.so.0 ,导致程序崩溃了。这个血案到底是怎么发生的呢?下面来分析分析 Linux上几乎所有动态库在编译时都指定了-soname,正是这个-soname引起的。基于这一点,我们来重现上面的错误。 步骤如下: 1.我们把tmp.c编译成库,指定它的库文件名为 libnewtmp.so.0 。 2.查看库文件的文件名等信息 3.使用生成的库文件(需要先生成一个软连接,因为在指定链接库时会这么写 -lnewtmp ,所以必须保证 libnewtmp.so 存在,在下面的演示中会看到) 4.设置库文件目录到环境变量中 5.运行程序,发现就可以还原上面的错误了。 [code]frog@u-server:~/test/so$ gcc tmp.c -fPIC -shared -Wl,-soname,libnewtmp.so.0 -o libnewtmp.so.0.0.1 frog@u-server:~/test/so$ frog@u-server:~/test/so$ readelf -d libnewtmp.so.0.0.1 Dynamic section at offset 0xe08 contains 25 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000e (SONAME) Library soname: [libnewtmp.so.0] 0x000000000000000c (INIT) 0x550 0x000000000000000d (FINI) 0x690 0x0000000000000019 (INIT_ARRAY) 0x200df0 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) 0x000000000000001a (FINI_ARRAY) 0x200df8 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) 0x000000006ffffef5 (GNU_HASH) 0x1f0 0x0000000000000005 (STRTAB) 0x368 0x0000000000000006 (SYMTAB) 0x230 0x000000000000000a (STRSZ) 183 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000003 (PLTGOT) 0x201000 0x0000000000000002 (PLTRELSZ) 48 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x520 0x0000000000000007 (RELA) 0x460 0x0000000000000008 (RELASZ) 192 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x000000006ffffffe (VERNEED) 0x440 0x000000006fffffff (VERNEEDNUM) 1 0x000000006ffffff0 (VERSYM) 0x420 0x000000006ffffff9 (RELACOUNT) 3 0x0000000000000000 (NULL) 0x0 frog@u-server:~/test/so$ frog@u-server:~/test/so$ gcc main.c -o main-new -L. -lnewtmp /usr/bin/ld: cannot find -lnewtmp collect2: error: ld returned 1 exit status frog@u-server:~/test/so$ ln -s libnewtmp.so.0.0.1 libnewtmp.so frog@u-server:~/test/so$ frog@u-server:~/test/so$ gcc main.c -o main-new -L. -lnewtmp frog@u-server:~/test/so$ frog@u-server:~/test/so$ export LD_LIBRARY_PATH=./ frog@u-server:~/test/so$ frog@u-server:~/test/so$ ./main-new ./main-new: error while loading shared libraries: libnewtmp.so.0: cannot open shared object file: No such file or directory frog@u-server:~/test/so$ frog@u-server:~/test/so$ frog@u-server:~/test/so$ ldd main-new linux-vdso.so.1 => (0x00007ffe27cf7000) libnewtmp.so.0 => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f49a8553000) /lib64/ld-linux-x86-64.so.2 (0x0000558fbffce000) frog@u-server:~/test/so$[/code] 我们使用ldd命令时发现,main程序依赖的动态库名字是libnewtmp.so.0,既不是libnewtmp.so也不是libnewtmp.so.0.0.1。其实在生成main程序的过程有如下几步: 链接器通过编译命令-L. -lnewtmp在当前目录查找libnewtmp.so文件 读取libnewtmp.so链接指向的实际文件,这里是 libnewtmp.so.0.0.1 读取libnewtmp.so.0.0.1中的SONAME,这里是 libnewtmp.so.0 将libnewtmp.so.0 记录到main程序的二进制数据里,运行时会去寻找该库文件 也就是说libnewtmp.so.0已经存储到main程序的二进制数据里了,不管这个程序在哪里,通过ldd查看它依赖的动态库都是 libnewtmp.so.0。运行时,这个名称的库文件必须存在,否则就报错。 问题找到了。 解决办法就是: 创建一个软连接 libnewtmp.so.0 指向 libnewtmp.so.0.0.1 即可。
请先 登录 后评论

2 个回答

长的
楼主分析的很厉害
请先 登录 后评论
百问网-钟老师
厉害了
请先 登录 后评论
  • 0 关注
  • 1 收藏,1097 浏览
  • 勤奋的小青蛙 提出于 2017-10-06 12:53

相似问题