有时候程序运行在不同的linux发行版本上一个正常,一个出错,引起的原因可能是某个共享库比较老旧,对比它在不同的系统上运行时依赖的库版本就可以知道引起错误可能的原因。那么如何知道一个程序运行时依赖哪些共享库呢?
一.查看程序依赖的共享库
1.使用ldd命令
首先得了解ldd是用来做什么的,需要注意什么,直接man,
描述:
ldd用来打印程序运行时的依赖的共享库,或者打印一个指定的共享库它又依赖于哪些共享库。
注意事项:
通常情况下,ldd调用标准的动态链接器(linux下的ld-linux.so.xx,它一般是一个位于/lib目录下的符号链接文件),将环境变量中 LD_TRACE_LOADED_OBJECTS 值为1,看名字就直到,它是控制允许跟踪加载对象的一个变量。但是需要注意的是,某些版本的ldd它获取依赖库信息时是通过直接执行程序的方式。也就是说,你最好不要将ldd用在一个不可信任的可执行程序上,因为这可能会由于执行这个不可信的程序引发安全问题。一个更安全的方法是通过使用objdump来获取信息:
objdump -p /path/to/program | grep NEEDED
常用选项:
--version Print the version number of ldd. -v --verbose Print all information, including, for example, symbol versioning information. -u --unused Print unused direct dependencies. (Since glibc 2.3.4.) -d --data-relocs Perform relocations and report any missing objects (ELF only). -r --function-relocs Perform relocations for both data objects and functions, and report any missing objects or functions (ELF only). --help Usage information.
注意到上面红色文字,在看看ldd程序的本质:
thomas@thomas-laptop:~/test/libld$ whereis ldd ldd: /usr/bin/ldd /usr/bin/X11/ldd /usr/share/man/man1/ldd.1.gz thomas@thomas-laptop:~/test/libld$ file /usr/bin/ldd /usr/bin/ldd: Bourne-Again shell script, ASCII text executable
它其实就是一个shell脚本,通过调用ld-linux.so.xx,并将环境变量 LD_TRACE_LOADED_OBJECTS设置为1,使用完毕后,再将这个环境变量unset,对应的其他选项诸如-v -u -d -r都是通过设置 LD_VERBOSE LD_WARN LD_BIND_NOW 这些个环境变量或者它们的组合来实现的,分析下ldd这个脚本就知道了。
2.使用ld-linux.so.x
可能不同的平台这个文件路径和名字不一样,man下ld.so可以看到详细信息。基本用法:
ld-linux.so.x [OPTIONS] [PROGRAM [ARGUMENTS]]
这里稍微需要注意下,program可以是elf文件,或者一个so库,必须指定其路径,绝对路径或者相对路径均可。主要用的选项是 --list
3.使用objdump
objdump可以分析对象文件的信息,或者反汇编对象文件。既然是可以反汇编对象文件,那么可以猜测对象文件必须是包含一堆机器码的文件,所谓object文件,参见wiki上的定义Object file,大致就是说一堆机器码再加一些描述信息,而机器码呢又是relocatable,就是说机器码的各个模块最终在内存中如何分布可以通过描述信息来确定。一般linux下就是elf格式的文件,比如编译形成的可执行文件,*.o *.a *.so ,这一类的文件。
通过 objdump -p objectfile | grep NEEDED来获得运行时所需共享库。
4. readelf
objdump用法类似,不过参数是 -d
5.pmap
只是不知道arm是否可以移植这个命令,它可以查看一个正在运行的进程的内存使用情况,那么也就看到了加载到内存中的共享库,只是它可能看不到完整的依赖库,这要看程序是怎么链接共享库的。共享库分为2种加载方式,1.程序运行前一次性全部加载完毕 2.当程序运行到某个点时,通过调用一些API来加载所需动态库。其实这里的这个动态库和共享库格式无区别,只是加载方式,时间点,不同罢了。如果是采用第一种方式,那么pmap可以看到完整的依赖,若是后者则可能看到的依赖库不完整。
二.查找库的位置
使用ldconfig -p | grep "your lib",ldconfig也是一个shell脚本,查看这个脚本可以看出真正执行的是ldconfig.real这个文件,它可以获取缓冲在/etc/ld.so.cache中的的库信息。