ldd - 列出可执行文件或共享目标文件的动态依赖项
ldd [-cDfilLpsvVw] [-d | -r] [-e envar] [-S dir] [-U | -u] file...
ldd 实用程序列出可执行文件和共享目标文件的动态依赖项。ldd 使用运行时链接程序 ld.so.1(1) 生成诊断信息。该运行时链接程序获取正在检查的文件并将其准备妥当,正如在正在运行的进程中将发生的一样。
缺省情况下,ldd 触发与正在检查的文件关联的所有共享目标文件的装入。这些依赖项包括所有“懒惰”依赖项、延迟依赖项和 filtee。因此,ldd 报告最大可能依赖项集。但是,在正常进程执行过程中,只有在引用依赖项时才会装入延迟装入的依赖项、延迟依赖项和 filtee。例如,许多系统库提供了广泛的功能,并且这些功能需要支持依赖项。ldd 报告所有此类依赖项,但在正常的进程执行过程中,可能不需要这些支持依赖项。请参见“用法”部分下的“延迟装入”以及《Oracle Solaris 11.4 Linkers and Libraries Guide》中的 "Lazy Loading of Dynamic Dependencies"。
ldd 以其最简单的方式分析正在接受检查的目标文件的依赖项要求。还可以指示 ldd 分析每个目标文件的重定位要求,这将使符号引用绑定到符号定义。
如果 file 是共享目标文件,则 ldd 需要该文件具备执行权限。如果该文件不具备执行权限,ldd 在尝试处理文件前会发出警告。
不会执行 ldd 检查的动态目标文件。因此,ldd 不会列出使用 dlopen(3C) 显式附加的任何共享目标文件。
要显示由某个进程或核心文件使用的所有目标文件,请使用 pldd(1)。
支持以下选项:
禁用对任何配置文件的使用。配置文件可用来更改缺省搜索路径,提供备选的目标文件依赖项。请参见 crle(1)。
跳过延迟依赖项装入。缺省情况下,ldd 会强制处理延迟依赖项和“懒惰”依赖项。另请参见 –L 选项。在正常进程执行过程中,只有在第一次引用延迟依赖项时才会装入延迟依赖项。当使用了 –D 选项时,使用 –d 或 –r 选项不会触发任何延迟依赖项装入操作。请参见 ld(1) 的 –z deferred 选项。
缺省情况下,ldd 不报告延迟的 filtee。请参见 –l 选项。
检查立即引用。请参见“用法”下的“接口验证”部分。
设置环境变量 envar。
此选项对于试用由运行时链接程序识别并可能会对 ldd 产生负面影响的环境变量(如 LD_PRELOAD)非常有用。
此选项还可用来仅从正在检查的目标文件(例如 LD_DEBUG)提取附加信息。请参见 ld.so.1(1)。
强制 ldd 检查不安全的可执行文件。超级用户调用 ldd 时,缺省情况下,ldd 不会处理任何不安全的可执行文件。如果可执行文件指定的解释程序没有驻留在 /lib 或 /usr/lib 下,则不会将可执行文件视为安全的文件。如果无法确定解释程序,也不会将可执行文件视为安全的文件。请参见“用法”下的“安全性”部分。
显示初始化部分的执行顺序。使用 –d 或 –r 选项时可能会影响所发现的顺序。请参见“用法”下的“初始化顺序”部分。
启用延迟装入。缺省情况下,ldd 会强制处理“懒惰”依赖项和延迟依赖项。另请参见 –D 选项。在正常的进程执行期间,延迟装入是缺省操作模式。在此情况下,任何“懒惰”依赖项或延迟依赖项仅在对延迟目标文件中定义的符号进行引用时才会装入到进程中。–d 或 –r 选项与 –L 选项一起使用时,可用于检查依赖项及其在正在运行的进程中的装入顺序。请参见 ld(1) 的 –z lazyload 选项。
强制对任何过滤器立即进行处理,以便列出所有 filtee 及其依赖项。立即处理过滤器是 ldd 的缺省操作模式。然而,在此缺省模式下,任何延迟的 filtee 或无法找到的辅助 filtee 会被忽略,且不进行任何提示。使用 –l 选项,延迟的 filtee 将与缺失的辅助 filtee 一起列出。
显示任何无法解析的显式父和外部引用。请参见“用法”下的“外部接口”部分。
检查立即引用和延迟引用。请参见“用法”下的“接口验证”部分。
指定要应用于路径搜索定位的所有目标文件的系统根。缺省情况下,路径搜索相对于系统根目录 / 进行解释。
显示用于定位共享目标文件依赖项的搜索路径。
显示任何未引用或未使用的依赖项。如果未引用的依赖项未由随 file 装入的其他目标文件绑定,则该依赖项将标记为未使用。没有从循环外部的目标文件绑定的循环依赖项也会被视为未引用的依赖项。此选项还会显示任何未使用的搜索路径。请参见“用法”下的“未使用的材料”部分。
显示任何未使用的目标文件。请参见“用法”下的“未使用的材料”部分。
显示处理 file 时引起的所有依赖项关系。此选项还会显示任何依赖项版本要求。请参见 pvs(1)。
输出版本信息并立即退出。
显示任何无法解析的弱符号引用。请参见“用法”下的“弱引用”部分。
输出用法消息并立即退出。
共享目标文件可以引用应当由共享目标文件的调用者提供的符号。在创建共享目标文件时,可以显式将这些引用归类为可从父代使用的引用,或将其简单地归类为外部引用。请参见 ld(1) 的 –M mapfile 选项以及 PARENT 和 EXTERN 符号定义关键字。
检查动态可执行文件时,无法解析的对父代或外部的依赖项引用会标记为错误。检查共享目标文件时,系统不会将无法解析的父代或外部引用标记为错误。
–p 选项在与 –d 或 –r 选项一起使用时,会将无法解析的父代或外部引用标记为错误。
动态目标文件装入进程时,将执行此目标文件提供的所有初始化代码。各个目标文件的初始化代码的执行顺序根据这些目标文件的依赖项关系确定。请参见《Oracle Solaris 11.4 Linkers and Libraries Guide》中的 "Initialization and Termination Routines"。
ldd 可以显示它装入的目标文件的初始化顺序。此分析在发现循环依赖项时非常有用。正常进程中装入依赖项的确切顺序可能会有所不同,因此运行时实际进行的初始化也可能会与 ldd 列出的不同。
受所用选项的影响,未显式定义所需依赖项的目标文件可能会看到 ldd 显示的初始化部分的顺序有所不同。例如,简单的应用程序可能会显示:
example% ldd -i main libA.so.1 => ./libA.so.1 libc.so.1 => /lib/libc.so.1 libB.so.1 => ./libB.so.1 init object=./libB.so.1 init object=./libA.so.1 init object=/lib/libc.so.1
然而,当应用了重定位时,初始化部分的顺序为:
example% ldd -ir main ......... init object=/lib/libc.so.1 init object=./libB.so.1 init object=./libA.so.1
在此情况下,libB.so.1 会引用 /lib/libc.so.1 中的函数。但是,libB.so.1 对此库没有显式依赖关系。仅当发现了重定位后才会建立依赖关系。此隐式依赖关系会影响初始化部分的顺序。
通常,在应用程序执行时建立的初始化部分的顺序等同于使用 –d 选项的 ldd。如果所有目标文件都完整地定义了其依赖项,则可以获得最佳顺序。构建动态目标文件时,建议使用 ld(1) 选项 –z defs 和 –z ignore。
一个或多个动态目标文件彼此引用时,会产生循环依赖关系。应当避免循环依赖关系,因为无法为这些循环依赖项建立唯一的初始化排序顺序。
ldd 可以检查正在接受检查的目标文件的符号引用和符号定义的兼容性。指定了 –d 和 –r 选项时,ldd 可以针对将 file 装入进程时会出现的任何未解析符号引用输出警告信息。
每次调用 ldd 期间,选项 –d 和 –r 两者只能指定其一。
立即引用通常针对可执行或共享目标文件代码使用的数据项。立即引用同时也是函数指针,甚至是通过与位置相关的共享目标文件执行的函数调用。延迟引用通常是通过与位置无关的共享目标文件进行的全局函数调用,或者是通过可执行文件进行的外部函数调用。有关这些引用类型的更多信息,请参见《Oracle Solaris 11.4 Linkers and Libraries Guide》中的 "When Relocations Are Performed"。
此外,目标文件装入也受重定位处理的影响。有关更多详细信息,请参见“用法”下的“延迟装入”部分。
可通过建立“懒惰”依赖项和延迟依赖项直接应用延迟装入。请参见 ld(1) 的 –z lazyload 选项和 –z deferred 选项。延迟装入也可以通过过滤器间接应用。请参见 ld(1) 的 –f 选项和 –F 选项。受所用选项的影响,采用延迟装入技术的目标文件在 ldd 输出中可能会变化。如果目标文件将其所有依赖项都表示为延迟依赖项,ldd 的缺省操作是按依赖项在该目标文件中的记录顺序列出所有依赖项:
example% ldd main libelf.so.1 => /lib/libelf.so.1 libnsl.so.1 => /lib/libnsl.so.1 libc.so.1 => /lib/libc.so.1
使用 –L 选项时,可以启用在运行时使用此目标文件时发生的延迟装入行为。在此模式下,延迟依赖项在对延迟目标文件中定义的符号进行引用时装入。因此,结合使用 –L 选项与 –d 和 –r 选项可以显示分别满足立即引用和延迟引用所需的依赖项:
example% ldd –L main example% ldd –d main libc.so.1 => /lib/libc.so.1 example% ldd –r main libc.so.1 => /lib/libc.so.1 libelf.so.1 => /lib/libelf.so.1
请注意,在本例中,依赖项的列出顺序不同于未使用选项时 ldd 显示的顺序。即使使用了 –r 选项,对依赖项的延迟引用的顺序可能也不同于在正在运行的进程中的引用顺序。
观察延迟装入也可以查明满足任何引用时不需要的目标文件。这类目标文件(在本例中,为 libnsl.so.1)可以从用来构建要检查的目标文件的链接行中删除。
只有已知要检查的可执行文件值得信任时,超级用户才应使用 –f 选项。超级用户对不可信任的可执行文件使用 –f 会危害系统安全。如果可执行文件的可信度未知,则超级用户应该暂时变为一般用户。然后,以一般用户身份调用 ldd。
只要不使用 :r 子命令,使用 dump(1)、elfdump(1)、elfedit(1) 和 mdb(1) 就可以安全地检查不可信任的目标文件。此外,非超级用户可以使用 mdb 的 :r 子命令或 truss(1) 检查不可信任的可执行文件,同时又不会构成太大的安全风险。针对不可信任的可执行文件使用 ldd、mdb :r 或 truss 时,要最大程度地降低风险,请使用 UID "nobody"。
ldd 可以验证依赖项使用情况。仅当某个符号引用绑定到了依赖项时,才认为依赖项已被使用。通过 –U 选项和 –U 选项,ldd 可针对装入 file 时装入的任何未引用或未使用的依赖项输出警告信息。这些选项在检查符号引用时很有用。如果 –r 选项未生效,则会自动启用 –d 选项。
由目标文件定义的但未从该目标文件绑定的依赖项称为未引用的依赖项。在装入 file 时未由任何其他目标文件绑定的依赖项称为未使用的目标文件。
依赖项可能位于缺省系统位置,也可能位于必须由搜索路径指定的位置。可以全局指定搜索路径,例如使用环境变量 LD_LIBRARY_PATH。此外,也可以在动态目标文件中将搜索路径定义为 runpath。请参见 ld(1) 的 –R 选项。不能用于满足任何依赖项的搜索路径会导致不必要的文件系统处理工作。
每次调用 ldd 期间,选项 –U 或 –u 两者只能指定其一,尽管 –U 是 –u 的超集。使用 –r 选项时发现的未引用或未使用的目标文件应当从依赖项中删除。这些目标文件未提供引用,但在装入 file 时会导致不必要的开销。使用 –d 选项时发现的任何未引用或未使用的目标文件都不是装入 file 时立即需要的。这些目标文件是延迟装入的候选者。有关更多详细信息,请参见“用法”下的“延迟装入”部分。
删除未使用的依赖项可以降低运行时链接开销。删除未引用的依赖项可以进一步降低运行时链接开销。不过,在与其他目标文件一起使用时或在会衍生其他目标文件依赖项时,删除未引用的依赖项可防止有未使用的依赖项。
删除未使用的搜索路径会减少定位依赖项时需做的工作量。通过网络访问文件服务器中的文件时,这可以节省大量的工作量。请注意,搜索路径可以编码到目标文件中,以满足 dlopen(3C) 的要求。由于可能不需要通过搜索路径获取此目标文件的依赖项,因此,在 ldd 看来,它是未使用的。
重定位使用的符号可以定义为弱引用。缺省情况下,如果弱符号引用无法解析,则会忽略重定位,并将零写入到重定位偏移。–w 选项在与 –d 或 –r 选项一起使用时,会将针对弱符号引用的任何无法解析的重定位标记为重定位错误。
有关下列属性的说明,请参见 attributes(7):
|
crle(1)、dump(1)、elfdump(1)、elfedit(1)、kldd(1)、ld(1)、ld.so.1(1)、mdb(1)、pldd(1)、pvs(1)、truss(1)、dlopen(3C)、 attributes(7)
《Oracle Solaris 11.4 Linkers and Libraries Guide》
ldd 将共享目标文件路径名记录输出到 stdout。还可以选择将符号解析问题的列表输出到 stderr。如果 file 不是可执行文件或共享目标文件,或者无法打开 file 进行读取,则将返回非零退出状态。
为共享目标文件使用 –d 或 –r 选项可能会产生误导性结果。ldd 会对共享目标文件执行最坏情形分析。然而,实际上,报告为无法解析的符号的符号可以由引用共享目标文件的可执行文件解析。可以使用运行时链接程序预装入机制为正在检查的目标文件添加依赖项。请参见 LD_PRELOAD。