Linux/Unix 工具 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 命令查找到脚本所在位置。使用 vim 打开 ldd 脚本。

vim `which ldd`

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

try_trace() (
  output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $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 变为空的时候才会结束,即执行 export LD_TRACE_LOADED_OBJECTS=0export LD_TRACE_LOADED_OBJECTS= 并不会将其置空。应该使用

unset LD_TRACE_LOADED_OBJECTS

取消该环境变量。

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; then
        dummy=`$rtld 2>&1`
        if test $? = 127; then
            verify_out=`${rtld} --verify "$file"`
            ret=$?
            case $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="$LD_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

补充

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

objdump -p /path/binfile | grep NEEDED

版权声明:
作者:dorence
链接:https://wp.dorence.top/archives/113
来源:极客模拟
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录