链接程序和库指南

重定位符号查找

运行时链接程序负责搜索目标文件在运行时所需的符号。此符号搜索基于请求目标文件的符号搜索范围,以及进程中每个目标文件所提供的符号可见性。装入目标文件时,可将这些属性作为缺省属性应用。此外,也可将这些属性作为 dlopen(3C) 的特定模式提供。在某些情况下,可在生成目标文件时将这些属性记录在目标文件中。

通常,用户应该熟悉应用于动态可执行文件及其依赖项的缺省搜索模型,以及应用于通过 dlopen(3C) 获取的目标文件的缺省搜索模型。前者将在下一节缺省符号查找中概述,后者(也可使用各种符号查找属性)将在符号查找中介绍。

动态库使用直接绑定时,将提供替代的符号查找模型。此模型指示运行时链接程序直接在链接编辑时提供符号的目标文件中搜索符号。 请参见直接绑定

缺省符号查找

动态可执行文件及随其装入的所有依赖项都被指定了 world 搜索范围和 global 符号可见性。 请参见符号查找。针对动态可执行文件或随其装入的任何依赖项的符号查找会导致搜索每个目标文件。运行时链接程序将从动态可执行文件开始,并按目标文件的装入顺序搜索每个依赖项。

如以上各节中所述,ldd(1) 将按依赖项的装入顺序列出动态可执行文件的依赖项。例如,共享库 libbar.so.1 需要符号 foo 的地址来完成重定位。动态可执行文件 proglibbar.so.1 指定为其依赖项之一。


$ ldd prog

        libfoo.so.1 =>   /home/me/lib/libfoo.so.1

        libbar.so.1 =>   /home/me/lib/libbar.so.1

运行时链接程序首先会在动态可执行文件 prog 中查找 foo,然后在共享库 /home/me/lib/libfoo.so.1 中查找,最后在共享库 /home/me/lib/libbar.so.1 中查找。


注 –

符号查找操作的开销可能很大,尤其是在符号名称大小和依赖项数目增加的情况下。这方面的性能将在性能注意事项中详细介绍。有关替代查找模型,请参见直接绑定


缺省重定位处理模型还允许转换为延迟装入 (lazy loading) 环境。如果在当前装入的目标文件中找不到某符号,则会处理所有暂挂的延迟装入目标文件,以尝试查找该符号。此装入是对尚未完整定义其依赖项的目标文件的补偿。但是,该补偿可能会破坏延迟装入的优点。

插入

缺省情况下,运行时链接程序首先在动态可执行文件中搜索符号,然后在每个依赖项中进行搜索。使用此模型时,第一次出现的所需符号满足搜索要求。因此,如果同一符号存在多个实例,则会在所有其他实例中插入第一个实例。

简单解析中概述了插入如何影响符号解析。缩减符号范围中提供了有关更改符号可见性,从而减少意外插入几率的机制。

如果目标文件被显式标识为插入项,则可以对每个目标文件强制执行插入。使用环境变量 LD_PRELOAD 装入或通过链接编辑器的 -z interpose 选项创建的任何目标文件都会标识为插入项。运行时链接程序搜索符号时,将在应用程序之后、任何其他依赖项之前搜索标识为插入项的任何目标文件。

仅当在进行任何进程重定位之前装入了插入项的情况下,才能保证可以使用插入项提供的所有接口。在重定位处理开始之前,将装入使用环境变量 LD_PRELOAD 提供的插入项,或作为应用程序的非延迟装入依赖项建立的插入项。启动重定位之后,引入进程中的插入项会降级为正常依赖项。如果插入项是延迟装入的,或者是由于使用 dlopen(3C) 而装入的,则插入项可能会降级。可使用 ldd(1) 来检测前一种类别。


% ldd -Lr prog

        libc.so.1 =>     /lib/libc.so.1

        foo.so.2 =>      ./foo.so.2

        libmapmalloc.so.1 =>     /usr/lib/libmapmalloc.so.1

        loading after relocation has started: interposition request \

                (DF_1_INTERPOSE) ignored: /usr/lib/libmapmalloc.so.1

注 –

如果链接编辑器在处理延迟装入的依赖项时遇到显式定义的插入项,则插入项将被记录为非延迟可装入依赖项。


直接绑定

使用直接绑定的目标文件维护符号引用与提供定义的依赖项之间的关系。运行时链接程序使用此信息直接搜索关联目标文件中的符号,而不执行缺省符号搜索模型。只能对使用链接编辑指定的依赖项建立直接绑定信息。因此,建议使用 -z defs 选项。

可使用下列机制之一建立符号引用与符号定义的直接绑定。

直接绑定可以大大降低由于包含许多符号重定位与依赖项的动态进程而导致的符号查找开销。此模型还允许在已直接绑定到的不同目标文件中查找同名的多个符号。


注 –

通过将环境变量 LD_NODIRECT 设置为非空值,可在运行时禁用直接绑定。


缺省符号搜索模型允许将符号的所有引用绑定到某个定义。由于直接绑定忽略缺省搜索模型,因此直接绑定禁用隐式插入符号。但是,在搜索提供符号定义的目标文件之前,会先搜索任何显式标识为插入项的目标文件。显式插入项包括使用环境变量 LD_PRELOAD 装入的目标文件,或使用链接编辑器的 -z interpose 选项创建的目标文件。 请参见插入

某些接口可为缺省技术提供替代实现。这些接口期望其实现成为该技术在进程内的唯一实例。例如 malloc(3C) 系列。malloc() 系列实现有多种,并且每个系列都期望成为进程中使用的唯一实现。应该避免直接绑定到此类系列中的接口,否则同一进程可能会引用该技术的多个实例。例如,进程中的一个依赖项可针对 libc.so.1 直接绑定,而另一个依赖项可针对 libmapmalloc.so.1 直接绑定。对 malloc()free() 的两种不同实现的不一致使用很可能会产生错误。

提供期望成为进程中的单一实例的接口的目标文件应该避免直接绑定到其接口。为防止任何调用方直接绑定到某接口,可以使用下列机制之一标记该接口。

非直接标记禁止任何符号引用直接绑定到实现。用于满足引用要求的符号搜索将使用缺省符号搜索模型。在生成随 Solaris 提供的各种 malloc() 系列实现时,使用了非直接标记。


注 –

NODIRECT mapfile 指令可与命令行选项 -B direct-z direct 组合使用。未显式定义 NODIRECT 的符号位于该命令行指令之后。同样,DIRECT mapfile 指令也可与命令行选项 -B nodirect 组合使用。未显式定义 DIRECT 的符号位于该命令行指令之后。