链接程序和库指南

缺省符号查找模型

对于通过 dlopen(3C) 添加的每个目标文件,运行时链接程序将首先在动态可执行文件中查找符号,之后,在进程初始化期间提供的每个目标文件中查找。如果找不到该符号,运行时链接程序将继续搜索。接下来,运行时链接程序会在通过 dlopen(3C) 获取的目标文件及其依赖项中查找。

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

在以下示例中,动态可执行文件 prog 和共享库 B.so.1 具有下列依赖项。


$ ldd prog

        A.so.1 =>        ./A.so.1

$ ldd B.so.1

        C.so.1 =>        ./C.so.1

如果 prog 通过 dlopen(3C) 获取共享库 B.so.1,则会首先在 prog 中查找重定位共享库 B.so.1C.so.1 所需的任何符号,然后依次在 A.so.1B.so.1C.so.1 中进行查找。在此简单示例中,将通过 dlopen(3C) 获取的共享库视作已在对应用程序的原始链接编辑结束时将它们添加进来。例如,可以采用图解方式表示前面列表中引用的目标文件,如下图所示。

图 3–1 单个 dlopen() 请求

单个 dlopen() 请求。

通过 dlopen(3C) 获取的目标文件(显示为阴影块)所需的任何符号查找,将从动态可执行文件 prog 继续执行一直到最后一个共享库 C.so.1

此符号查找是按装入目标文件时为目标文件指定的属性建立的。请记住,已为动态可执行文件及随其装入的所有依赖项指定了全局符号可见性,并且为新目标文件指定了全局符号搜索范围。因此,新目标文件能够在原始目标文件中查找符号。新目标文件也会构成一个唯一的组,其中每个目标文件都具有局部符号可见性。因此,该组中的每个目标文件都可在其他组成员中查找符号。

这些新目标文件不会影响应用程序或其初始目标文件依赖项所需的正常符号查找。例如,如果 A.so.1 要求在执行了前面的 dlopen(3C) 后进行函数重定位,则运行时链接程序对重定位符号的正常搜索是首先在 prog 中查找,然后在 A.so.1 中查找。运行时链接程序不会继续在 B.so.1C.so.1 中查找。

此符号查找同样是按装入目标文件时为目标文件指定的属性建立的。对于动态可执行文件及随其装入的所有依赖项,都指定全局符号搜索范围。此范围不允许它们在仅提供局部符号可见性的新目标文件中查找符号。

这些符号搜索和符号可见性属性用于维护目标文件之间的关联。这些关联基于它们引入进程地址空间的情况以及目标文件之间的依赖项关系。将与给定 dlopen(3C) 关联的目标文件指定给唯一的组,可以确保仅允许与同一 dlopen(3C) 关联的目标文件在目标文件本身及其关联的依赖项中查找符号。

定义目标文件之间的关联的概念在多次执行 dlopen(3C) 的应用程序中更为清晰。例如,假定共享库 D.so.1 具有以下依赖项:


$ ldd D.so.1

        E.so.1 =>         ./E.so.1

并且 prog 应用程序使用 dlopen(3C) 装入此共享库及共享库 B.so.1。下图说明了目标文件之间的符号查找关系。

图 3–2 多个 dlopen() 请求

多个 dlopen() 请求。

假定 B.so.1D.so.1 都包含符号 foo 的定义,C.so.1E.so.1 都包含需要此符号的重定位。由于目标文件与唯一的组关联,因此 C.so.1 绑定到 B.so.1 中的定义,而 E.so.1 绑定到 D.so.1 中的定义。此机制用于为通过多次调用 dlopen(3C) 获取的目标文件提供最直观的绑定。

在到现在为止已介绍的情况中使用目标文件时,执行每个 dlopen(3C) 的顺序对生成的符号绑定没有影响。但是,如果目标文件具有公共依赖项,则生成的绑定可能会受到进行 dlopen(3C) 调用的顺序的影响。

在以下示例中,共享库 O.so.1P.so.1 具有相同的公共依赖项。


$ ldd O.so.1

        Z.so.1 =>        ./Z.so.1

$ ldd P.so.1

        Z.so.1 =>        ./Z.so.1

在此示例中,prog 应用程序将对其中每个共享库执行 dlopen(3C)。由于共享库 Z.so.1O.so.1P.so.1 的公共依赖项,因此将为与两次 dlopen(3C) 调用关联的两个组指定 Z.so.1。此关系如下图所示。

图 3–3 具有公共依赖项的多个 dlopen() 请求

具有公共依赖项的多个 dlopen() 请求。

Z.so.1 可同时供 O.so.1P.so.1 用于查找符号。更重要的是,就 dlopen(3C) 排序而言,Z.so.1 还可用于同时在 O.so.1P.so.1 中查找符号。

因此,如果 O.so.1P.so.1 同时包含符号 foo 的定义(这是 Z.so.1 重定位所需的),则进行的实际绑定不可预测,因为它会受到 dlopen(3C) 调用的顺序的影响。如果符号 foo 的功能在定义它的两个共享库间不同,则在 Z.so.1 中执行代码的整体结果可能会因应用程序的 dlopen(3C) 排序而异。