分层的ldd(1)

58

由于使用Gentoo,通常会出现在更新后程序链接到旧版本的库的情况。通常情况下,revdep-rebuild可以帮助解决这个问题,但这次是对Python库的依赖关系,而python-updater无法识别。

是否有一种“分层”变体的ldd,它可以显示哪个共享库依赖于另一个共享库?大多数情况下,库和可执行文件仅链接到少量其他共享库,这些共享库反过来又链接到少量库,从而将库依赖关系转化为一个大列表。我想知道我必须使用另一个库的新版本重新构建的依赖关系。

4个回答

119

我看到许多有趣的细节,但没有直接回答问题。

ldd 的“分层”版本是 lddtree(来自 app-misc/pax-utils):

$ lddtree /usr/bin/xmllint 
xmllint => /usr/bin/xmllint (interpreter => /lib64/ld-linux-x86-64.so.2)
    libreadline.so.6 => /lib64/libreadline.so.6
        libncurses.so.5 => /lib64/libncurses.so.5
            libdl.so.2 => /lib64/libdl.so.2
    libxml2.so.2 => /usr/lib64/libxml2.so.2
        libicui18n.so.49 => /usr/lib64/libicui18n.so.49
            libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/32/libstdc++.so.6
                ld-linux.so.2 => /lib64/ld-linux.so.2
            libgcc_s.so.1 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/32/libgcc_s.so.1
        libicuuc.so.49 => /usr/lib64/libicuuc.so.49
        libicudata.so.49 => /usr/lib64/libicudata.so.49
        libz.so.1 => /lib64/libz.so.1
        liblzma.so.5 => /usr/lib64/liblzma.so.5
        libm.so.6 => /lib64/libm.so.6
    libpthread.so.0 => /lib64/libpthread.so.0
    libc.so.6 => /lib64/libc.so.6

10
您,先生,是我的英雄。感谢提到“lddtree”,我已经寻找这样的工具有一段时间了。 - ack
不错,我之前不知道 :) - rkachach
2
lddtree在这里:https://github.com/gentoo/pax-utils/blob/master/lddtree.py(还有一个fork在https://github.com/ncopa/lddtree,使用sh而不是python编写)。 - Jonathan Wakely
在Ubuntu上,使用命令sudo apt install pax-utils来获取lddtree - Chris Seymour

26
如果您正在运行 Portage≥2.2,使用FEATURES=preserve-libs,那么您几乎不需要再使用revdep-rebuild了,因为旧的.so.版本将根据需要保留(尽管您仍需要仔细重建,因为当libA.so.0需要libC.so.0libB.so.0需要libC.so.1时,还是会出现问题,并且某些二进制文件同时需要libA.so.0libB.so.0)。
话虽如此,ldd所做的就是让动态链接器像往常一样加载可执行文件或库,并在此过程中打印一些信息。这是一个递归的“二进制文件需要库需要其他库”搜索,因为这就是动态链接器的工作原理。
我目前正在运行 Linux/ppc32;在 Linux/x86 上,动态链接器通常是/lib/ld-linux.so.2,而在 Linux/x86_64 上,动态链接器通常是/lib/ld-linux-x86-64.so.2。在这里,我直接调用它,只是为了强调ldd无非是一个调用动态链接器执行其操作的 shell 脚本。
$ /lib/ld.so.1 /sbin/badblocks
使用方法: /sbin/badblocks [-b 块大小] [-i 输入文件] [-o 输出文件] [-svwnf]
       [-c 同时检查块数] [-d 读取之间的延迟因子] [-e 最大坏块数]
       [-p 检查次数] [-t 测试模式 [-t 测试模式 [...]]]
       设备 [最后块 [第一块]]
$ LD_TRACE_LOADED_OBJECTS=1 /lib/ld.so.1 /sbin/badblocks
        linux-vdso32.so.1 =>  (0x00100000)
        libext2fs.so.2 => /lib/libext2fs.so.2 (0x0ffa8000)
        libcom_err.so.2 => /lib/libcom_err.so.2 (0x0ff84000)
        libc.so.6 => /lib/libc.so.6 (0x0fdfa000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x0fdc0000)
        /lib/ld.so.1 (0x48000000)
$ LD_TRACE_LOADED_OBJECTS=1 /lib/ld.so.1 /lib/libcom_err.so.2
        linux-vdso32.so.1 =>  (0x00100000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x6ffa2000)
        libc.so.6 => /lib/libc.so.6 (0x6fe18000)
        /lib/ld.so.1 (0x203ba000)
$ grep -l pthread /sbin/badblocks /lib/libcom_err.so.2
/lib/libcom_err.so.2

/sbin/badblocks并没有把libpthread.so.0列为库依赖项,但它被libcom_err.so.2所引用。

你的问题是ldd没有输出一个好看的依赖树?使用ldd -v

$ LD_TRACE_LOADED_OBJECTS=1 LD_VERBOSE=1 /lib/ld.so.1 /sbin/badblocks
        linux-vdso32.so.1 =>  (0x00100000)
        libext2fs.so.2 => /lib/libext2fs.so.2 (0x0ffa8000)
        libcom_err.so.2 => /lib/libcom_err.so.2 (0x0ff84000)
        libc.so.6 => /lib/libc.so.6 (0x0fdfa000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x0fdc0000)
        /lib/ld.so.1 (0x201f9000)
版本信息: /sbin/badblocks: libc.so.6 (GLIBC_2.2) => /lib/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/libc.so.6 libc.so.6 (GLIBC_2.1) => /lib/libc.so.6 libc.so.6 (GLIBC_2.0) => /lib/libc.so.6 libc.so.6 (GLIBC_2.3.4) => /lib/libc.so.6 /lib/libext2fs.so.2: libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/libc.so.6 libc.so.6 (GLIBC_2.3) => /lib/libc.so.6 libc.so.6 (GLIBC_2.2) => /lib/libc.so.6 libc.so.6 (GLIBC_2.1) => /lib/libc.so.6 libc.so.6 (GLIBC_2.0) => /lib/libc.so.6 /lib/libcom_err.so.2: ld.so.1 (GLIBC_2.3) => /lib/ld.so.1 libpthread.so.0 (GLIBC_2.1) => /lib/libpthread.so.0 libpthread.so.0 (GLIBC_2.0) => /lib/libpthread.so.0 libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/libc.so.6 libc.so.6 (GLIBC_2.1) => /lib/libc.so.6 libc.so.6 (GLIBC_2.0) => /lib/libc.so.6 /lib/libc.so.6: ld.so.1 (GLIBC_PRIVATE) => /lib/ld.so.1 ld.so.1 (GLIBC_2.3) => /lib/ld.so.1 /lib/libpthread.so.0: ld.so.1 (GLIBC_2.3) => /lib/ld.so.1 ld.so.1 (GLIBC_2.1) => /lib/ld.so.1 ld.so.1 (GLIBC_PRIVATE) => /lib/ld.so.1 libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6 libc.so.6 (GLIBC_2.3.4) => /lib/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/libc.so.6 libc.so.6 (GLIBC_2.1) => /lib/libc.so.6 libc.so.6 (GLIBC_2.3.2) => /lib/libc.so.6 libc.so.6 (GLIBC_2.2) => /lib/libc.so.6 libc.so.6 (GLIBC_PRIVATE) => /lib/libc.so.6 libc.so.6 (GLIBC_2.0) => /lib/libc.so.6

如果您愿意,可以直接阅读ELF头文件,而不依赖于动态链接器。
示例代码如下:
``` $ readelf -d /sbin/badblocks | grep NEEDED 0x00000001 (NEEDED) Shared library: [libext2fs.so.2] 0x00000001 (NEEDED) Shared library: [libcom_err.so.2] 0x00000001 (NEEDED) Shared library: [libc.so.6] $ readelf -d /lib/libcom_err.so.2 | grep NEEDED 0x00000001 (NEEDED) Shared library: [libpthread.so.0] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x00000001 (NEEDED) Shared library: [ld.so.1] ```
您还可以查看man ld.so以了解其他有趣的技巧,您可以使用它来玩转glibc的动态链接器。

1
ldd -v 命令的树状部分仅显示具有版本化符号的库。 - marcin

18

жҲ‘йңҖиҰҒзұ»дјјзҡ„дёңиҘҝпјҢжүҖд»ҘжҲ‘еҶҷдәҶtlddпјҢиҝҷйҮҢеұ•зӨәе®ғиҮӘе·ұзҡ„еә“дҫқиө–пјҡ

$ ./tldd ./tldd
./tldd
в””в”Җlibstdc++.so.6 => /lib64/libstdc++.so.6 (0x0000003687c00000)
  в”ңв”Җlibm.so.6 => /lib64/libm.so.6 (0x0000003685000000)
  в”Ӯ в””в”Җlibc.so.6 => /lib64/libc.so.6 (0x0000003684c00000)
  в”Ӯ   в””в”Җld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x0000003684400000)
  в””в”Җlibgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003686c00000)

дҪ д№ҹеҸҜд»ҘдҪҝз”Ёldd -vжқҘжҹҘзңӢжүҖжңүе…ұдә«еә“зҡ„жүҖжңүдҫқиө–йЎ№пјҢдҪҶе®ғдёҚдјҡжҳҫзӨәеұӮж¬Ўз»“жһ„ж ‘гҖӮ


@erwin,是什么阻止了你让它工作? - Jonathan Wakely
谢谢。由于某些原因,我没有收到有关该项目的GitLab电子邮件,但我将在本月晚些时候解决它。 - Jonathan Wakely
1
我刚试了一下tldd的最新更新,效果非常好!是一个很棒的小实用工具! - erwin
我今天看到我的老板在使用它,我以前从未听说过它。因此看起来它很受欢迎。 - Sridhar Sarnobat
对于某些库,我在使用tlddlddtree(pax-utils)时得到了稍微不同的依赖树。不确定哪一个是最终的版本。 - ontherocks
对于一些库,我用tlddlddtree(pax-utils)得到了稍有不同的依赖树。不确定哪一个是最终的。 - undefined

-2
我也想建议使用 "readelf -d",但请确保已经使用 LDFLAGS="-Wl,--as-needed" 进行构建,如果还没有的话。这样可以减少遇到这个问题的次数。Portage 2.2 的 preserve-libs 很好,但我了解到它主要被屏蔽是因为它有缺陷。

现在这些缺陷都很小,顺便说一下,我想一个月前就应该更仔细地看看它们了,哈哈。 - Michał Górny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接