*nix 工具 ldd 介绍



  • ldd

    ldd = List Dynamic Dependencies

    ldd(1) 用于列出程序运行时需要依赖的动态链接库。

    SYNOPSIS

    ldd [option]... binfile...
    

    OPTIONS

    --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.
    

    源码分析

    此命令为一个 shell 脚本。可以使用 which 命令查找到脚本所在位置。使用如下指令可以打开 ldd 脚本。

    vim `which ldd`
    

    脚本中最主要的函数为 try_trace()

    try_trace() (
      output=(eval(eval add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit rc)rc=rc)
      rc=?
      printf '%s' "${output%x}"
      return $rc
    )
    

    其中 $add_env 的关键值为 LD_TRACE_LOADED_OBJECTS=1。经过查阅资料,该环境变量不为空时,任何可执行程序在运行时只显示依赖,而程序本身并不真正执行。所以 ldd 相当于以下命令(不带其他参数时),

    export add_env="LD_TRACE_LOADED_OBJECTS=1";
    $add_env /path/binfile
    

    LD_TRACE_LOADED_OBJECTS 是由 ld.so(8) (elf动态库装载器)实现的。ld.so(8) 在发行版中一般为 ld-linux.so(2)ldd 源码中使用数组 $RTLDLIST 索引 ld-linux.so(2)

    RTLDLIST="/lib/ld-linux.so.2 /lib64/ld-linux-x86-64.so.2 /libx32/ld-linux-x32.so.2"
    
    RTLD=
    ret=1
    for rtld in ${RTLDLIST}; do
        if test -x rtld;thendummy=rtld; then
            dummy=`rtld 2>&1`
            if test ?=127;thenverifyout=? = 127; then
                verify_out=`{rtld} --verify "$file"`
                ret=$?
                case retin[02])RTLD=ret in
                    [02]) RTLD={rtld}; break;;
                esac
            fi
        fi
    done
    

    即当系统存在 /lib/ld-linux.so.2 时,调用其作为依赖加载库,若没有则依次索引 /lib64/ld-linux-x86-64.so.2/libx32/ld-linux-x32.so.2。在一般的 64 位 SELinux 中都有 /lib64/ld-linux-x86-64.so.2。所以使用如下命令也可以达到相同的效果:

    export RTLD=/lib64/ld-linux-x86-64.so.2
    $RTLD --list /path/binfile
    

    这也可以解释为什么 /lib64/ld-linux-x86-64.so.2 几乎出现在所有依赖动态库程序的依赖中。(没有装载器,无法装载动态库)

    最后再来看一下 ldd 脚本中实现的其它功能。(环境变量非空时使能,即 LD_WARN=yesLD_WARN=1 都可)

    option addtional $add_env description
    -v, --verbose LD_VERBOSE=yes 打印所有附加信息
    -u, --unused LD_DEBUG=\"LDDEBUGLD_DEBUG{LD_DEBUG:+,}unused\" 打印编译需要但未使用的库
    -d, --data-relocs LD_WARN=yes 打印丢失的库
    -r, --function-relocs LD_WARN=yes LD_BIND_NOW=yes 打印丢失的库和函数

    总结

    ldd 脚本相当于以下命令,

    LD_TRACE_LOADED_OBJECTS=1 /path/binfile
    

    或者使用 ld-linux.so(2)

    /lib64/ld-linux-x86-64.so.2 --list /path/binfile
    


  • 如果使用 export LD_TRACE_LOADED_OBJECTS=1,则会进入“依赖查询模式”,所有可执行文件都会变为执行对应的 ldd

    需要注意的是,当 LD_TRACE_LOADED_OBJECTS 变为空的时候才会结束,即执行 export LD_TRACE_LOADED_OBJECTS=0export LD_TRACE_LOADED_OBJECTS= 并不会将其置空。应该使用

    unset LD_TRACE_LOADED_OBJECTS
    


  • 根据官方文档,为了保证安全性,可以使用如下命令检查未知安全性的代码,

    objdump -p /path/binfile | grep NEEDED
    

 

Copyright © 2018 bbs.dian.org.cn All rights reserved.

与 Dian 的连接断开,我们正在尝试重连,请耐心等待