当前位置:首页 > 文章列表 > 文章 > linux > Linux ldd 怎样找出缺失的共享库依赖

Linux ldd 怎样找出缺失的共享库依赖

来源:17golang原创 2026-11-12 10:23:35 0浏览 收藏

我第一次遇到“程序明明存在,却提示找不到某个 .so 文件”时,先看了应用自己的日志,后来才发现真正有用的线索在依赖解析结果里。Linux 的 ldd 会把目标程序需要的共享对象以及解析到的路径列出来;其中出现 not found,通常就是当前环境没有为该依赖找到可用文件。

官方手册地址:https://man7.org/linux/man-pages/man1/ldd.1.html

这篇只解决一个问题:怎样用 ldd 找出缺失依赖,并判断是库文件不在搜索路径、重定位失败,还是目标文件本身不适合直接交给 ldd。涉及不可信二进制时,会切换到静态的 objdump -p 读取。

先读懂 ldd 输出中的三种状态

我现在排查这类问题,会先把输出分成三类,而不是一看到某一行就开始安装软件包:

  • 已解析路径:类似 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6,说明动态链接器为这个名字找到了文件。
  • not found:依赖名字被目标文件声明了,但按当前搜索规则没有找到对应对象。
  • 特殊对象:linux-vdso.so.1、动态链接器本身等并不等同于普通磁盘库,不能简单按普通 .so 文件处理。
ELF目标、ldd、动态链接器与直接间接依赖及not found结果的静态关系说明图
图1:ldd 依赖解析关系说明图;看“解析结果”分组即可区分已解析路径和 not found,这是一张静态说明图,不是终端截图。

官方 ldd(1) 手册说明,ldd 展示的是程序或共享对象所需的共享库;常见实现会让动态链接器在跟踪模式下检查这些依赖。因此它呈现的是“当前环境如何解析”,不只是目标文件里写着哪些名字。

用 not found 锁定真正缺失的库

先保存目标路径,再只筛选缺失行。下面的命令没有替读者决定安装哪个包,作用只是把证据从长输出中提出来:

target="/opt/example/bin/app"

# 只筛选动态链接器明确标记为未解析的依赖。
ldd "$target" | grep -F 'not found'

如果没有任何输出,并不等于程序一定能启动。它只说明 ldd 没有在这次检查中报告未找到的共享对象。还要留意:

  • 目标可能不是当前架构可运行的 ELF 文件;
  • 依赖可能存在,但符号版本或重定位阶段仍不匹配;
  • 程序在启动后通过 dlopen 动态加载的库,不一定出现在最初的依赖清单里。

如果输出是 libexample.so => not found,先记下库的名字和目标文件,不要直接把一个同名文件复制到系统目录。下一步应解释动态链接器会去哪里找。

结合搜索路径解释为什么会找不到

动态链接器的规则决定了同一个程序在不同机器上可能得到不同路径。对不含斜杠的依赖名,官方 ld.so(8) 文档列出的关键来源包括 DT_RPATH、LD_LIBRARY_PATH、DT_RUNPATH、/etc/ld.so.cache 以及默认目录;具体优先级和安全执行模式也会影响结果。

target="/opt/example/bin/app"

# 查看目标的动态段,确认是否写入了 RPATH、RUNPATH 或 NEEDED。
# 这里看的是文件声明,不把它当成完整的运行时依赖树。
readelf -d "$target" | grep -E 'NEEDED|RPATH|RUNPATH'

# 临时显示当前 shell 是否带入了库搜索路径,避免把环境差异误判成缺库。
printf 'LD_LIBRARY_PATH=%s\n' "${LD_LIBRARY_PATH-}"

我会把证据分成两层:NEEDED 说明目标声明了什么,ldd 说明当前环境把这些声明解析成了什么。若只有某个部署用户报错,优先比较该用户的环境变量、服务启动方式和安全执行条件。

特别要注意空的 LD_LIBRARY_PATH 项可能代表当前工作目录,路径顺序也会让同名库被不同目录中的文件满足。生产修复应回到构建时的 RUNPATH、系统库缓存或明确的部署目录,而不是把临时环境变量永久写进服务。

区分缺库与重定位错误

有时依赖文件能被找到,但加载其中的数据或函数仍然失败。这时可以用 ldd 的重定位检查选项把问题再缩小一层:

target="/opt/example/bin/app"

# 检查数据重定位,适合确认缺失对象或数据符号。
ldd -d "$target"

# 同时检查函数重定位;输出可能比普通 ldd 更长。
ldd -r "$target"

-d 会执行数据重定位检查,-r 会连函数重定位一起检查。我的判断习惯是:

现象优先怀疑下一步
=> not found库文件或搜索路径缺失核对 RUNPATH、缓存和部署目录
库路径已出现,但重定位报错符号、ABI 或版本不匹配比较符号版本与构建环境
普通 ldd 正常,启动后仍报错运行期动态加载或环境差异再看程序的加载逻辑与服务环境

不可信文件不要直接交给 ldd

这里是我后来最在意的一条边界:官方手册明确提醒,不要对不可信的可执行文件直接运行 ldd。在某些情况下,旧版本或特殊 ELF 解释器可能触发直接执行行为。目标文件来源不明时,先用静态方式读取它声明的直接依赖:

不可信ELF在ldd动态观察与objdump静态读取之间的安全边界说明图
图2:ldd 与 objdump -p 的安全边界说明图;它表达“完整依赖树”和“直接 NEEDED”的差别,不是截图或实际执行结果。
target="/path/to/untrusted-file"

# 对来源不明的 ELF,优先静态读取直接依赖声明。
# NEEDED 只代表目标文件直接声明的共享对象,不等于完整依赖树。
objdump -p "$target" | grep -F 'NEEDED'

这个替代方案的取舍很明确:objdump -p 更适合先做静态筛查,但它只显示直接依赖;ldd 能展开更完整的依赖树,却要求你信任目标文件和当前工具链的行为。两者不能当成完全等价的命令。

我的可复用排障清单

  1. 确认目标是预期架构的 ELF 文件,并记录绝对路径。
  2. 对可信目标运行 ldd target,先找 not found。
  3. 把 NEEDED、RPATH/RUNPATH 和当前库路径分开记录。
  4. 若路径已解析但仍失败,再用 ldd -d 或 ldd -r 看重定位。
  5. 目标不可信时停止使用 ldd,改用 objdump -p | grep NEEDED。
  6. 修复后重新检查同一个目标和同一个服务启动环境,确认不是只修好了交互式 shell。

对我来说,ldd 最有价值的地方不是“列出几个库”,而是把启动错误拆成了可观察的依赖解析证据。只要把 not found、搜索路径、重定位和文件信任边界分开,排查通常就不会退化成盲目复制 .so 文件。

相关问题

ldd 没有 not found,为什么程序仍然启动失败?

可能是符号版本、重定位、运行后 dlopen,或服务启动环境和当前 shell 不同。继续看 ldd -r、动态段和实际服务环境。

objdump -p 能完全替代 ldd 吗?

不能。它更适合不可信文件的静态筛查,只展示直接 NEEDED;ldd 侧重当前环境下的完整解析树。

看到 not found 可以直接设置 LD_LIBRARY_PATH 吗?

可以作为短时诊断手段,但生产修复应明确库的部署位置和构建时 RUNPATH,并评估路径顺序和安全执行模式,避免环境变量掩盖真正的打包问题。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
systemd-delta 怎样找出被覆盖的 unit 配置systemd-delta 怎样找出被覆盖的 unit 配置
上一篇
systemd-delta 怎样找出被覆盖的 unit 配置
Linux udevadm info 怎样读取设备属性
下一篇
Linux udevadm info 怎样读取设备属性
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    992次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    995次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1117次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1091次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    932次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码