【问题标题】:ldd weirdness on old binariesldd 对旧二进制文件的怪异
【发布时间】:2025-12-29 23:40:07
【问题描述】:

我对 ldd 有以下奇怪之处

$ sudo ldd ./monit 
    not a dynamic executable

$ readelf -d monit 

Dynamic section at offset 0x25ea90 contains 27 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libpam.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libcrypt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libresolv.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libnsl.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
...

$ file ./monit 
./monit: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.0, with debug_info, not stripped

$ uname -r -i -m
4.15.0-43-generic x86_64 x86_64


$ file $(which ls)
/bin/ls: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=9567f9a28e66f4d7ec4baf31cfbf68d0410f0ae6, stripped

其他二进制文件和库是针对更新的内核/系统编译的,ldd 成功报告了共享库,我想知道不同环境之间是否存在任何不兼容性,尽管二进制文件构建在相同的架构上.. 另一个愚蠢的问题是,如果某些共享库会像 libpam 一样升级,那么如果不插入旧库,二进制文件就有可能无法运行,api 是否可能会发生如此大的变化?如果新版本向后兼容,那么为旧名称创建新的动态链接 (ln) 还不够吗?

-- 最新的-- 真是个……白痴。我忘记了我拒绝了该主机上分区的执行权限:( ldd 命令按预期工作

【问题讨论】:

  • 为什么是 sudo?
  • 我不确定我是否也在没有 sudo 的情况下尝试过,我目前无法进行进一步测试,我今晚会再试一次,谢谢
  • 你没有说明问题。什么是奇怪的行为?
  • 我希望在 ldd 输出中得到动态库列表(由 readelf 显示)
  • @Shawn 在没有 sudo 的情况下得到相同的错误消息

标签: c linux shared-libraries ldd


【解决方案1】:

尽管二进制文件构建在相同的架构上,但不同环境之间是否存在任何不兼容性

程序所依赖的“环境”是许多小东西放在一起的大词。它是一种体系结构(即支持 cpu 的指令集)或类似的体系结构(主板结构、cpu 到内存结构等)或类似的操作系统细节(例如具有 GNU 扩展的 POSIX 兼容系统或具有 dos 的 DOS 系统.h 库)。 Environment 也是库版本,因为它们的 api 可以更改,并且还喜欢环境变量(好吧,如果环境中存在的话)。

知道“如果不同环境之间存在任何不兼容”,您必须手动检查两个版本之间的所有更改。人们使用版本控制作为一种可靠且糟糕的方式来告知某些情况发生了变化。然后,您必须查看文档,以查看以人类可读方式发生的变化。然后你必须去源代码,看看真正改变了什么。

如果某些共享库会像 libpam 一样升级,那么在不插入旧库的情况下,二进制文件可能无法运行,api 是否会发生如此大的变化?

首先请注意,大多数 unix 程序都在 GNU 许可下:

本程序不提供任何保证

没有人会保证它在任何情况下都能正常工作。也就是说,它可能。它可能不会。世界上有很多不同的库,它们是由不同的人编写的,而且它们都经常更改 api,它可能无法正常工作。它可能会起作用。视情况而定。

为确保 api 不会发生太大变化,聪明的人写信给standards。和standards。和standards。和标准....

另一方面是开发人员,他们免费完成所有艰苦的工作。他们需要更改 api,以便引入新的好功能或修复错误。所以他们稍微改变了api。这可能会破坏依赖该 API 的旧程序。

如果新版本向后兼容,那么为旧名称创建一个新的动态链接 (ln) 还不够吗?

我这样做的次数比我想承认的要多(主要是用旧的 libpng 运行 eagle),而且大多数情况下它都有效。试试吧,(通常,在普通的 unix 下,以用户身份运行,具有良好的权限)可能发生的最糟糕的事情是你的程序会出现段错误(好吧,在 sudo 下可能发生的最糟糕的事情是对你的硬件和擦除造成永久性损坏的所有数据)。

大多数(不是全部)GNU/Linux 系统使用 glibc 作为 C 标准库的实现。这应该是最稳定的 api,因为所有 C 程序都依赖它。而且它changes too 并不总是向后兼容。

【讨论】:

  • 感谢详尽的回答。但我不明白为什么 readelf 显示了共享库列表,而 ldd 给出了警告消息。无论如何,我需要将 monit 版本锁定到一个稳定的测试版本,如果可能的话让升级它的共享库。如果我使用从升级中排除 monit 的包管理器,它将锁定其依赖项升级。也许最好的策略是完全避免共享库并静态重新编译它......
  • 现在人们使用docker,因为它比静态编译更容易设置。如果可以,请使用静态编译。如果您绑定到使用特定内核版本的特定监视器版本,请为它设置一个虚拟机。 package manager excluding monit - 如果上游没有给你更新的包,你可以重新编译它(毕竟是 linux)。 monit 看起来更新了。
  • 在我回答你之后,我意识到我是从一个没有执行授权的分区启动 ldd 命令的。我用正确的权限重新启动它,现在 ldd 就像一个魅力一样工作。非常感谢您的宝贵时间和有用的提示