SO(共享对象)编号如何工作?

SO(共享对象)编号如何工作?

我知道Linux下的共享对象使用“so number”,即共享对象的不同版本被赋予不同的扩展名,例如:

  • example.so.1
  • example.so.2

我理解这个想法是拥有两个不同的文件,以便系统上可以存在两个版本的库(而不是 Windows 上的“DLL Hell”)。我想知道这在实践中是如何运作的?我经常看到这example.so实际上是指向最新版本的example.so.2符号链接。.2那么依赖旧版本的应用程序如何example.so正确识别它呢?是否有任何规则规定必须使用哪些数字?或者这只是惯例?与 Windows 中软件二进制文件在系统之间传输不同,如果系统具有更新版本的共享对象,那么在从源代码编译时,它会自动链接到旧版本吗?

我怀疑这与相关,ldconfig但我不确定如何。

答案1

二进制文件本身知道它们依赖于哪个版本的共享库,并专门请求它。您可以使用ldd来显示依赖关系;我的ls是:

$ ldd /bin/ls
    linux-gate.so.1 =>  (0xb784e000)
    librt.so.1 => /lib/librt.so.1 (0xb782c000)
    libacl.so.1 => /lib/libacl.so.1 (0xb7824000)
    libc.so.6 => /lib/libc.so.6 (0xb76dc000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb76c3000)
    /lib/ld-linux.so.2 (0xb784f000)
    libattr.so.1 => /lib/libattr.so.1 (0xb76bd000)

正如您所看到的,它指向 例如libpthread.so.0,而不仅仅是libpthread.so


之所以使用符号链接是为了链接器。当您想直接链接时libpthread.so,您可以给出gcc标志-lpthread,它会自动添加lib前缀和.so后缀。您无法告诉它添加后缀.so.0,因此符号链接指向最新版本的库以方便添加

答案2

共享库中的数字是 Linux 中用来标识库的 API 的约定。通常格式为:

libFOO.so.MAJOR.MINOR

正如您所注意到的,通常有一个从 libFOO.so 到 libFOO.so.MAJOR.MINOR 的符号链接。 ldconfig 负责将此链接更新到最新版本。

当 API 更改(新入口点被删除或参数或类型更改)时,MAJOR 通常会递增。 MINOR 通常会在错误修复版本或引入新 API 且不破坏现有 API 时增加。

更广泛的讨论可以在这里找到:剖析共享库

答案3

共享库应根据以下方案进行版本控制:

blah.so.X.Y.Z

在哪里

  • X = 向后不兼容的 ABI 版本
  • Y = 向后兼容的 ABI 版本
  • Z = 仅内部更改 - ABI 没有更改

通常,您只会看到第一个数字,hello.so.1因为第一个数字是识别库的“版本”所需的唯一数字,因为所有其他数字都是向后兼容的。

ldconfig维护一个表,其中列出系统上可用的共享库以及该库的路径所在的位置。您可以通过运行以下命令来验证这一点:

ldconfig -p

当为 Red Hat 之类的东西构建包时,将在 RPM 构建时查找二进制文件中调用的共享库并将其添加为包的依赖项。因此,当您安装该软件包时,安装程​​序将hello.so.1通过检查 来查找系统上是否已安装该软件包ldconfig

您可以通过执行以下操作来查看包的依赖关系:

rpm -qpR hello.rpm

该系统(与 Windows 不同)允许hello.so在系统上安装多个版本,并同时由不同的应用程序使用。

答案4

libNAME.so 是编译器/链接器首次查找 -lNAME 指定的库时使用的文件名。共享库文件内部有一个名为 SONAME 的字段。当构建过程首次将库本身链接到共享对象 (so) 时,会设置此字段。该 SONAME 实际上是链接器在可执行文件中存储的内容,具体取决于与其链接的共享对象。通常,SONAME 的形式为 libNAME.so.MAJOR,并且只要库与链接到它的现有可执行文件不兼容,就会更改,并且可以根据需要保留安装库的两个主要版本(尽管只会指向一个版本进行开发)如 libNAME.so)此外,为了支持在库的次要版本之间轻松升级,libNAME.so.MAJOR 通常是指向 libNAME.so.MAJOR.MINOR 等文件的链接。可以安装新的次要版本,一旦完成,旧次要版本的链接将被跳转到新的次要版本,立即升级所有新执行以使用升级后的库。另请参阅我的回答Linux、GNU GCC、ld、版本脚本和 ELF 二进制格式 -- 它是如何工作的?

相关内容