在内存中装入动态目标文件时,将会检查该目标文件的任何其他依赖项。缺省情况下,将立即装入存在的所有依赖项。此循环会一直继续,直到找遍整个依赖项树为止。最后,解析由重定位指定的所有目标文件间数据引用。无论应用程序在执行期间是否引用了这些依赖项中的代码,都会执行这些操作。
在延迟装入模型中,标记为延迟装入的所有依赖项仅在显式引用时装入。通过利用函数调用的延迟绑定,依赖项装入将会一直延迟,直到第一次引用该函数。因此,绝不会装入从不引用的目标文件。
重定位引用可以是即时的,也可以是延迟的。因为初始化目标文件时必须解析即时引用,所以必须即时装入满足此引用要求的任何依赖项。因此,将这类依赖项标识为延迟可装入几乎没有效果。请参见执行重定位的时间。通常,建议不要在动态目标文件之间进行即时引用。
链接编辑器对调试库 liblddbg 的引用将使用延迟装入。由于不会经常进行调试,因此每次调用链接编辑器时装入此库既无必要又需要很大开销。通过指示可以延迟装入此库,处理库的开销将转至要求调试输出的那些调用。
实现延迟装入模型的替代方法是在需要时使用 dlopen() 和 dlsym() 来装入并绑定到依赖项。如果 dlsym() 引用数很少,则此模型非常理想。如果在链接编辑时不知道依赖项名称或位置,则此模型也很适用。对于与已知依赖项的更复杂交互,对正常符号引用进行编码并指定要延迟装入的依赖项更为简单。
通过链接编辑器选项 –z lazyload 和 –z nolazyload,可将目标文件分别指定为延迟装入或正常装入。这些选项在链接编辑命令行中与位置相关。该选项之后的任何依赖项都将采用其指定的装入属性。缺省情况下,–z nolazyload 选项有效。
以下简单程序具有依赖项 libdebug.so.1。动态节 (.dynamic) 显示 libdebug.so.1 被标记为延迟装入。符号信息节 (.SUNW_syminfo) 显示触发 libdebug.so.1 装入的符号引用。
$ cc -o prog prog.c -L. -zlazyload -ldebug -znolazyload -lelf -R'$ORIGIN' $ elfdump -d prog Dynamic Section: .dynamic index tag value [0] POSFLAG_1 0x1 [ LAZY ] [1] NEEDED 0x123 libdebug.so.1 [2] NEEDED 0x131 libelf.so.1 [3] NEEDED 0x13d libc.so.1 [4] RUNPATH 0x147 $ORIGIN ... $ elfdump -y prog Syminfo section: .SUNW_syminfo index flgs bound to symbol .... [52] DL [1] libdebug.so.1 debug
值为 LAZY 的 POSFLAG_1 指示应该延迟装入下面的 NEEDED 项 libdebug.so.1。由于 libelf.so.1 没有前述的 LAZY 标志,因此该库将在程序初始启动时装入。
使用延迟装入时,可能需要准确声明在应用程序使用的目标文件中的依赖项和运行路径。例如,假定有两个目标文件 libA.so 和 libB.so,它们同时引用了 libX.so 中的符号。libA.so 将 libX.so 声明为依赖项,但 libB.so 未执行此操作。通常,将 libA.so 与 libB.so 一起使用时,libB.so 可以引用 libX.so,因为 libA.so 使此依赖项可用。但是,如果 libA.so 将 libX.so 声明为延迟装入,则在 libB.so 引用此依赖项时可能不会装入 libX.so。如果 libB.so 将 libX.so 声明为依赖项,但未能提供查找该依赖项所需的运行路径,则可能会出现类似错误。
无论是否延迟装入,动态目标文件都应声明其所有依赖项以及如何查找这些依赖项。对于延迟装入,此依赖项信息更为重要。