有时候会遇到这种问题,我在编译时指定了动态库 -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.运行程序,发现就可以还原上面的错误了。
- 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$
复制代码
我们使用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 即可。
0