ldd —— 查看可执行文件/库的动态库依赖
ldd 列出一个动态链接程序运行时需要加载哪些共享库(.so),以及它们被解析到的实际路径。排查"启动报 error while loading shared libraries / cannot open shared object"时的首选。
数据来源
- 来源对象:先读 ELF 的
.dynamic节拿到NEEDED直接依赖,再调用动态链接器ld.so实际做一遍符号解析,递归展开全部依赖及其解析到的路径。 - 采集方式:不是纯读文件——它借助 ld.so 走一遍真实的加载/查找流程(受
LD_LIBRARY_PATH、ld.so.cache等影响)。 - 由此决定的特性:⚠️ 因为会调用 ld.so 加载程序,对不可信二进制不安全(某些情况下可能触发执行);只想安全地看直接依赖,改用纯静态读的
readelf -d(见正文)。
bash
# glibc 自带,无需额外安装
ldd <file>一、用法与输出
bash
$ ldd ./cpu_demo
linux-vdso.so.1 (0x00007fff...) # 内核提供的虚拟 so,不是真实文件
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f...)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f...)
/lib64/ld-linux-x86-64.so.2 (0x00007f...) # 动态链接器本身每行:需要的库名 => 解析到的实际路径 (加载地址)。
=> not found→ 缺库,就是启动失败的原因,需装库或配LD_LIBRARY_PATH。linux-vdso.so.1没有路径是正常的(内核映射的虚拟库)。
二、not found 排查
bash
ldd ./myapp | grep 'not found' # 找出缺哪些库解决思路:
- 装缺的库(
apt install libxxx/yum install xxx)。 - 库在非标准路径 → 加到
/etc/ld.so.conf.d/xxx.conf后ldconfig,或临时export LD_LIBRARY_PATH=/opt/mylib:$LD_LIBRARY_PATH。 - 版本号对不上(要
libfoo.so.2只有libfoo.so.3)→ 装对应版本或建软链(谨慎)。
bash
ldconfig -p | grep libstdc++ # 查系统已注册的库缓存里有没有它三、⚠️ 安全警告
别对不信任的程序跑 ldd。ldd 的部分实现是真的把程序加载起来来解析依赖的,等于执行了它。分析来路不明的二进制时,改用不执行程序的安全方式:
bash
readelf -d ./suspicious | grep NEEDED # 只读 ELF 的 .dynamic 节,不执行程序(推荐)
objdump -p ./suspicious | grep NEEDED # 同样安全readelf -d 只列直接依赖(NEEDED 项);ldd 列递归的全部依赖(依赖的库还依赖谁)。想看直接依赖且安全,用 readelf。
四、结合本仓库
bash
make
ldd ./cpu_demo # 应看到 libstdc++、libc、libpthread(用了 std::thread)
readelf -d ./cpu_demo | grep NEEDED # 安全版:只看直接依赖cpu_demo 用了
std::thread,所以依赖libpthread(新版 glibc 已把 pthread 并入 libc,可能看不到独立的 libpthread)。Makefile 里-pthread就是为链接它。
五、相关
- 静态链接的程序(
-static)ldd会显示not a dynamic executable—— 没有外部依赖。 - 看某个
.so又依赖谁:ldd libfoo.so。 - 运行时到底加载了哪些库、从哪加载:
LD_DEBUG=libs ./cpu_demo会打印动态链接器的详细查找过程。
六、一句话总结
ldd 快速列出动态库依赖,not found 即缺库根因;但它可能触发执行文件,排查不可信二进制应改用 readelf -d。