运行时链接程序负责搜索目标文件在运行时所需的符号。通常,用户应该熟悉应用于动态可执行文件及其依赖项的缺省搜索模型,以及应用于通过 dlopen(3C) 获取的目标文件的缺省搜索模型。但是,目标文件的符号属性或是具体的绑定要求会导致符号查找结果具有更复杂的特性。
目标文件有两个属性会影响符号查找。第一个属性是请求目标文件的符号搜索作用域。第二个属性是进程中每个目标文件提供的符号可见性。
装入目标文件时,可将这些属性作为缺省属性应用。此外,也可将这些属性作为 dlopen(3C) 的特定模式提供。在某些情况下,可在生成目标文件时将这些属性记录在目标文件中。
目标文件可以定义一个全局搜索作用域和/或一个组搜索作用域。
目标文件可在同一组的任何目标文件中搜索符号。通过使用 dlopen(3C) 获取的目标文件或使用链接编辑器的 –B group 选项生成的目标文件创建的依赖项树构成一个唯一的组。
目标文件可以定义目标文件的导出符号是全局可见还是局部可见。
运行时符号搜索也可由符号可见性指定。指定了 STV_SINGLETON 可见性的符号不受任何符号搜索作用域的影响。所有的单件符号引用都绑定到进程中第一次出现的单件定义。请参见Table 12–23。
符号查找的最简单形式将在下一节缺省符号查找中进行概述。通常,符号属性由多种形式的 dlopen(3C) 使用。这些情况将在符号查找中进行讨论。
动态目标文件使用直接绑定时,将提供替代的符号查找模型。此模型指示运行时链接程序直接在链接编辑时提供符号的目标文件中搜索符号。请参见Chapter 6, 直接绑定。
动态可执行文件及随其装入的所有依赖项都被指定了 world(全局)搜索作用域和 global(全局)符号可见性。针对动态可执行文件或随其装入的任何依赖项的缺省符号查找会导致搜索每个目标文件。运行时链接程序将从动态可执行文件开始,并按目标文件的装入顺序搜索每个依赖项。
ldd(1) 将按依赖项的装入顺序列出动态可执行文件的依赖项。例如,假定动态可执行文件 prog 将 libfoo.so.1 和 libbar.so.1 指定为其依赖项。
$ ldd prog libfoo.so.1 => /home/me/lib/libfoo.so.1 libbar.so.1 => /home/me/lib/libbar.so.1
如果需要符号 bar 来执行重定位,运行时链接程序将首先在动态可执行文件 prog 中查找 bar。如果找不到符号,运行时链接程序随后会在共享目标文件 /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
可以使用 INTERPOSE mapfile 关键字将动态可执行文件中的单个符号定义为插入项。该机制使用 –z interpose 选项,因而更具选择性,并且针对随着依赖项发展而发生的逆向插入提供更好的隔离。请参见定义显式插入。