关于linux装载器(如何解决应用程序跑不起来not found等问题)
关于linux动态链接共享库(如何解决应用程序跑不起来not found等问题)
所谓linux中的Share Libraries和Dynamic linking扮演的角色类似Windows 中的dll文件一样。现在的OS操作系统中,大部分的程序都是动态链接的,就是说,很多程序在编译成可执行程序时,会共享一些库。这样会带来至少一个好处:应用程序可以减小自己的体积,对于各种各样的应用程序中的OS来说,可以大大减少很多存储空间了。
Linux中存在两种库类型。1. 一种称之为静态库。以.a 后缀。这种库本身在编译成目标文件的时候是和应用程序链接在一起的,所以编译出来的应用程序相对较大。
2. 第二种称之为动态链接共享库。 以.so为后缀。虽然这种库形式只有一种,但是在使用中可以有两种形式:
a. 运行(runtime)时动态链接,共享库在编译器编译时被链接,但并没有包括在应用程序中(目标程序中),只在运行时链接。而且是必要的,如果没有共享库,程序将跑不起来。
b. 运行中使用动态链接装载器中的函数来进行动态的加载、卸载或者链接。如浏览器使用中装载的各种插件。
我们知道Linux中的执行文件使用的一种叫做ELF格式来表示。这是一种特殊的二进制格式式。 ELF = Executable and Linkable Format,可执行链接格式,是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的。扩展名为elf。工具接口标准委员会(TIS)选择了正在发展中的ELF标准作为工作在32位INTEL体系上不同操作系统之间可移植的二进制文件格式。
在移植的linux中经常碰到自己移植的文件系统上经常会碰到,应用程序跑不起来,通常出现类似这样的错误:
-/bin/sh: xxx not found.
或者
xxx: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory
如果文件系统已经移植好,能正常使用其他应用程序。那显然是应用程序缺少了相关的库了。一句话就是共享库或动态链接出现了问题。
我们知道一个程序要想在内存中运行,除了编译之外还要经过链接和装入这两个步骤。当然linux中动态链接也是经过这三个过程。Linux 使用这个ld-linux.so*(我的平台是使用ld-linux.so6)中的来装载(其实这只是一个链接)其他库。所以这个库必须放在linux中/lib下。对于其他,通常我们共享库放在/lib这个路径下,而且也是系统默认的搜索路径。
Linux共享库的搜索路径先后顺序:
1、编译目标代码时指定的动态库搜索路径:在编译的时候指定-Wl,-rpath=路径
2、环境变量LD_LIBRARY_PATH指定的动态库搜索路径
3、配置文件/etc/ld.so.conf中指定的动态库搜索路径
4、默认的动态库搜索路径/lib
5、默认的动态库搜索路径 /usr/lib
解决思路:
#readelf -a <文件>
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00008034 0x00008034 0x000c0 0x000c0 R E 0x4
INTERP 0x0000f4 0x000080f4 0x000080f4 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.3]
LOAD 0x000000 0x00008000 0x00008000 0x0049c 0x0049c R E 0x8000
LOAD 0x00049c 0x0001049c 0x0001049c 0x000ec 0x00108 RW 0x8000
DYNAMIC 0x0004a8 0x000104a8 0x000104a8 0x000c0 0x000c0 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
发现程序默认使用[Requesting program interpreter: /lib/ld-linux.so.3]作为连接器,但是发现/lib目录下面并没有相关文件,所以无法装在执行文件
#man gcc
-muclibc
Use uClibc instead of the GNU C library. This is the default on *-*-linux-*uclibc* targets.
发现如果不加-muclibc这条命令的话,编译器默认是寻找GUN 的c library
于是在编译是加上了-muclibc
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00008034 0x00008034 0x000c0 0x000c0 R E 0x4
INTERP 0x0000f4 0x000080f4 0x000080f4 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-uClibc.so.0]
LOAD 0x000000 0x00008000 0x00008000 0x0049c 0x0049c R E 0x8000
LOAD 0x00049c 0x0001049c 0x0001049c 0x000ec 0x00108 RW 0x8000
DYNAMIC 0x0004a8 0x000104a8 0x000104a8 0x000c0 0x000c0 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
发现装载器终于变成了[Requesting program interpreter: /lib/ld-uClibc.so.0]
运行编译文件,成功!!!!
那么为什么当前gcc默认会指向/lib/ld-linux.so.3文件呢?
#arm-linux-gcc -dumpspecs >`arm-linux-gcc -print-libgcc-file-name `/specs
#vi specs
发现link中
*link:
%{!static:--eh-frame-hdr} %{h*} %{version:-v} %{b} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker %{muclibc:%{mglibc:%e-mglibc and -muclibc used together}/lib/ld-uClibc.so.0;:/lib/ld-linux.so.3}} -X %{mbig-endian:-EB} %{mlittle-endian:-EL} -m armelf_linux_eabi
包含/lib/ld-linux.so.3信息,好的,我们干掉他,替换成自己喜欢的吧,神马?不会修改?请参阅:http://blog.csdn.net/dragon101788/article/details/17509987
参考解决的思路,首先要却定自己编译的程序是否编译于目标平台的以及相关的信息然后设置好动链接共享库环境。结合例子helloarm程序。
wsn@wsn-Inspiron-1427:~/mylinux$ file helloarmhelloarm: ELF 32-bit LSB> Data>Description
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "4T"
Tag_CPU_arch: v4T
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-1
Tag_ABI_PCS_wchar_t: 4
Tag_ABI_FP_denormal: Needed
Tag_ABI_FP_exceptions: Needed
Tag_ABI_FP_number_model: IEEE 754
Tag_ABI_align_needed: 8-byte
Tag_ABI_enum_size: int
从以上可以看出helloarm程序的目标平台是ARMv4T,而且已经使用动态链接共享库。
查看应用程序所需要的库:
wsn@wsn-Inspiron-1427:~/mylinux$ readelf -d helloarm |grep NEEDED
Dynamic section at offset 0x5a8 contains 25 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.6]
…
所需要的库文件分别是: libgcc_s.so.1和libc.so.6
所以,最后我们将ld-linux-so6、libgcc_s.so.1、libc.so.6直接放到默认中/lib下面即可。当然也可以可以在/etc下新建ld.so.conf类似这样:
#/etc/ld.so.conf
/usr/X11R6/lib
/usr/lib
...
..
/usr/lib/sane
/usr/lib/mysql
/opt/lib
或者通过export LD_LIBRARY_PATH=路径:$LD_LIBRARY_PATHLl来自定义。
设置好之后,你的应用程序就可以跑起来了。He~
[root@WSN /]# ls
bin helloarm linuxrc proc sys var
dev home lost+found root tmp
etc lib mnt sbin usr
[root@WSN /]# ./helloarm
Hello arm !
I am running on GNU/linux !
Bye-Bye!
[root@WSN /]#
更多推荐
所有评论(0)