从ldd谈起 [linux演习]

来源:互联网 发布:网络电视机顶盒哪个好 编辑:程序博客网 时间:2024/06/01 23:08

ldd的原理


ldd 命令可以打印出ELF Executable文件的动态链接库依赖. 
如果了解ELF文件格式, 将非常容易理解系统连接器是如何加载so文件, 并链接启动一个ELF可执行文件的.   一句话来说: ldd命令的原理就是调用系统连接器, 修改连接器依赖的环境变量, 使得ELF加载时,让链接器输出具体需要哪些so文件, 由于linux上可执行文件为ELF格式, 所以ldd命令也就仅可以输出ELF文件的so依赖关系. 其他可执行文件格式, 比如a.out格式所的连接器同ELF文件连接器不同. 所以ldd命令无法处理a.out格式; 下面摘录了man ld.so的帮助信息, 其中列出了连接器以及连接器的用途. 可以看到ELF文件的链接器为/lib/ld-linux.so.1或者/lib/ld-linux.so.2  这里的1和2对应对应libc1和libc2两个c语言库. 而a.out格式则使用/lib/ld.so作为程序启动时加载动态so文件的链接器.

       /lib/ld.so              a.out dynamic linker/loader       /lib/ld-linux.so.{1,2}              ELF dynamic linker/loader       /etc/ld.so.cache              File containing a compiled list of directories in which to search for libraries and an ordered list of candidate libraries.       /etc/ld.so.preload              File containing a whitespace separated list of ELF shared libraries to be loaded before the program.       lib*.so*              shared libraries

正是基于以上原理, 我们其实可以非常简单的猜想到ldd命令的内部逻辑, 它只是简单校验命令行参数, 然后将参数最后传递给ld-linux.so文件, 利用链接器读取ELF文件中的so依赖关系而已. 所以在系统中ldd命令真的只是一个shell脚本, 不要惊讶于一个shell脚本有这样强大的功能, 这个脚本只是编译工具,链接工具某一个简单阶段的接口调用而已. 想真正的去了解连接器是如何工作的. 推荐各位仔细研读ELF文件格式. 明白了可读的文本最终如何被编译链接, 并加载启动的流程之后, 所有东西最终都无比明白.
顺便扯远一点:  一切知识最终都是历史, ELF文件格式也是这样. a.out提出之后, unix和DOS分裂之后, linux出现之后..gcc, gdb, 链接器..这些东西最后都植根与ELF文件格式, 这些工具一些生成ELF文件, 另外一些则读取其中一部分内容而已...二进制和操作系统的秘密都藏在ELF和ld-linux.so文件之后.
回到ldd的话题, 由于ELF展开之后实在内容太多, 我们还是专注于ldd周边工具.  与ldd命令类似的 链接器接周边工具, 还有ldconfig。

纵观ldd脚本的内容, 可以发现整个脚本除了基本参数校验之外, 唯一功能即设置变量LD_TRACE_LOADED_OBJECTS=1. 链接器工作时如果该变量有值,则输出动态跨信息。
add_env="LD_TRACE_LOADED_OBJECTS=1 LD_WARN=$warn LD_BIND_NOW=$bind_now"add_env="$add_env LD_LIBRARY_VERSION=\$verify_out"add_env="$add_env LD_VERBOSE=$verbose"if test "$unused" = yes; then  add_env="$add_env LD_DEBUG=\"$LD_DEBUG${LD_DEBUG:+,}unused\""fi# The following use of cat is needed to make ldd work in SELinux# environments where the executed program might not have permissions# to write to the console/tty.  But only bash 3.x supports the pipefail# option, and we don't bother to handle the case for older bash versions.if set -o pipefail 2> /dev/null; then  try_trace() {    eval $add_env '"$@"' | cat   }else  try_trace() {    eval $add_env '"$@"'  }fi

一个简单的模仿: 自己export LD_TRACE_LOADED_OBJECTS=1, 然后运行ls命令。。。



0 0
原创粉丝点击