和loadAndInit子程序

用途

将模块装入到当前过程中。

语法

int *load ( ModuleName, Flags, LibraryPath)
char *ModuleName;
uint Flags;
char *LibraryPath;
int *loadAndInit ( ModuleName, Flags, LibraryPath)
char *ModuleName;
uint Flags;
char *LibraryPath;

描述

loadloadAndInit 子例程将指定的模块装入到调用进程的地址空间中。 模块可以是常规文件,也可以是归档的成员。 将新模块添加到 32 位进程的地址空间时,装入操作可能会导致中断值发生更改。

负载 子例程不是用于装入 C++ 模块的首选方法。 改用loadAndInit子程序。 loadAndInit子程序使用与load相同的接口,但执行 C++ 初始化。

执行 子例程类似于 负载 子例程,但以下情况除外:

  • 负载 子例程不会将当前程序替换为新的程序。
  • exec 子例程没有显式库路径参数; 它只有 LIBPATHLD_LIBRARY_PATH 环境变量。 此外,当使用 执行 子例程的程序具有比调用者更多的特权 (例如,在使用 set-UID 程序的情况下) 时,将忽略这些库路径环境变量。

可以通过两种方式中的一种将大型应用程序拆分为一个或多个模块,以允许在同一进程中执行。 第一种方法是单独创建每个应用程序的模块,并在需要时使用 负载 来显式装入模块。 另一种方法是在通过定义导入和导出的符号创建模块时指定这些模块之间的关系。

模块可以从其他模块导入符号。 每当从一个或多个其他模块导入符号时,如果尚未装入必需的模块,并且未将导入的符号指定为延迟导入,那么将自动装入这些模块以解析符号引用。 这些模块可以是库或个别文件中的归档成员,并且可以具有共享或专用文件特征,以控制装入这些模块的方式和位置。

当共享模块 (通常是共享库归档的成员) 的访问许可权允许共享时,即当它们具有其他读许可权时,会将这些模块装入到共享库区域。 专用模块以及不具有共享所需许可权的共享模块将装入到流程专用区域中。

当装入器解析符号时,它使用与该符号一起记录的文件名来查找导出该符号的模块。 如果文件名包含任何 / (斜杠) 字符,那么将直接使用它,并且必须指定相应的文件或归档成员。 但是,如果文件名是基本名称 (不包含 / 个字符) ,那么装入器将在缺省库路径中指定的目录中搜索具有该基本名称的文件 (即,模块或归档)。

LibraryPath 是一个字符串,其中包含一个或多个以冒号分隔的目录路径名。 有关库路径搜索的信息,请参阅 正在搜索从属模块 部分。

当进程在 跟踪 控制下执行时,在 负载 处理完成后将重新复制该进程的部分地址空间。 对于 32 位进程,将重新复制主程序文本 1 在第 1 段中装入) 和共享库模块 (在第 13 段中装入)。 对这些段的任何断点或其他修改都必须在 负载 调用后重新插入。 对于 64 位进程,在执行 负载 调用后,将重新复制共享库模块。 将通过将 _SLWTED 标志设置为 所返回的状态来通知调试器,以便它可以重新插入断点。

当在 跟踪 控制下执行的进程调用 负载时,将通过在 返回的状态中设置 _SLWTED 标志来通知调试器。 新装入到共享库段中的任何模块都将复制到进程的这些段的专用副本中,以便调试器可以检查或修改这些模块。

负载 子例程将调用新模块及其任何从属项的初始化例程 (初始化 例程) (如果尚未装入这些例程)。

当进程终止或执行 执行 子例程时,此子例程装入的模块将自动卸装。 通过调用 卸载 子例程显式卸装它们。

正在搜索从属模块

装入操作和 exec 操作在其从属模块搜索机制方面略有不同。 在将模块添加到正在运行的进程 (装入操作) 的地址空间时,将使用下一节中概述的规则来查找指定的模块。 请注意,依赖关系可能松散定义为树,但模块之间也可能存在递归关系。 以下组件可能用于创建完整的库搜索路径:

  1. 如果设置了 L_LIBPATH_EXEC 标志,那么将显示在执行时使用的库搜索路径。
  2. LibraryPath 参数的值 (如果非空)。 请注意,空字符串是指引用当前工作目录的有效搜索路径。 如果 LibraryPath 参数为 NULL ,那么将改为使用 LIBPATH 环境变量的值,或者使用 LD_LIBRARY_PATH 环境变量 (如果未设置 LIBPATH )。
  3. 要装入的模块的装入程序部分中包含的库搜索路径 ( ModuleName 参数)。
  4. 包含在正在装入其直接从属项的模块的装入程序部分中的库搜索路径。 请注意,在搜索每个模块的直接从属项时,每个模块的信息都会更改。

要查找 ModuleName 模块,请使用组件 1 和 2。 要查找从属项,将按顺序使用组件 1 2 3 和 4。 请注意,如果已属于正在运行的过程的任何模块满足新装入的模块的依赖关系需求,那么不会再次装入预先存在的模块。

对于聚集搜索规范的每个冒号分隔部分,如果找不到基本名称,那么将继续执行搜索。 此外,如果需要的文件不是归档成员,那么搜索将继续经过具有错误对象方式的文件。 如果需要归档成员,那么在找到文件名的第一个匹配项时搜索将停止。 如果文件的格式不正确,或者如果归档不包含必需的归档成员,或者未导出必需符号的定义,那么将发生错误。 如果对从属模块指定了相对路径名或绝对路径名,那么不会执行库路径搜索。

模块中存储的库搜索路径是在链接编辑时指定的。

如果指定的模块具有非常长的依赖关系链 (例如, lib1.a,依赖于 lib2.a,依赖于 lib3.a等) ,那么 负载 子例程可能导致调用过程失败。 这是因为装入器在固定大小堆栈上以递归方式处理此类关系。 仅当处理具有一千多个元素的依赖关系链时,才会显示此限制。

参数

描述
ModuleName 指向所要装入的模块的名称。 模块名称由一个路径名以及一个可选成员名组成。 如果路径名至少包含 on/字符,那么将直接使用该名称,并且不会执行目录搜索以找到该文件。 如果路径名包含 no/characters ,那么它将被视为基本名称,并且应该位于库路径中列出的其中一个目录中。

如果不是空值,那么库路径为 LibraryPath 参数的值,或者为 LIBPATH 环境变量的值 (如果已设置; 否则为 LD_LIBRARY_PATH 环境变量 (如果已设置)) 或在进程执行时使用的库路径 (如果已设置 L_LIBPATH_EXEC )。 如果未提供任何库路径,那么模块应该位于当前目录中。

ModuleName 参数可以显式命名归档成员。 语法为 路径名(成员) ,其中 路径名 遵循上一段中指定的规则,而 成员 是特定归档成员的名称。 括号是规范的必需部分,并且不允许在中间插入空格。 如果指定了归档成员,那么必须将 _LOADMEMBER 标志添加到 标志 参数中。 否则,整个 ModuleName 参数将被视为显式文件名。

标志 修改 loadloadAndInit 服务的行为,如下所示 (请参阅 ldr.h 文件)。 如果不需要特殊行为,请将 flags 参数的值 0 为 0 (零)。 为实现兼容性,还可以指定值 1 (一)。
L_LIBPATH_EXEC
指定在进程执行时使用的库路径应该附加到 负载 调用中指定的任何库路径 (作为参数或环境变量)。 建议在对 负载 子例程进行的所有调用中指定此标志。
_LOADMEMBER
指示 ModuleName 参数可指定归档成员。 将在 ModuleName 参数中搜索括号,如果找到该参数,那么会将该参数视为 "文件名/成员名" 对。 如果存在此标志,并且 ModuleName 参数不包含括号,那么会将整个 ModuleName 参数视为文件名规范。 在任一条件下,都期望在库路径或当前目录中找到文件名。
_NOAUTODEFER
指定必须通过使用 装入绑定 子例程显式解析正在装入的模块中的任何延迟导入。 这允许稍后使用指定的模块显式解析未解析的导入。 如果未指定此标志,那么当任何后续装入的模块导出与未解析的导入匹配的符号时,最早会解析延迟导入 (标记为延迟解析)。
LibraryPath 指向用于指定缺省库搜索路径的字符字符串。

如果 LibraryPath 参数为 NULL ,那么将使用 LIBPATH 环境变量 (如果已设置); 否则,将使用 LD_LIBRARY_PATH 环境变量。

库路径用于定位指定为 basenames 的从属模块 (即,它们的路径名组件不包含/(斜杠) 字符)。

请注意将 LibraryPath 参数设置为空,并使 LibraryPath 参数指向空字符串 ("") 之间的差异。 空字符串是由单个目录 (当前目录) 组成的有效库路径。

返回值

成功完成后, loadloadAndInit 子例程将返回指向模块入口点的函数的指针。 如果该模块没有入口点,那么返回该模块的数据部分的地址。

错误代码

如果 loadloadAndInit 子例程失败,那么将返回空指针,不装入模块,并设置 errno 全局变量以指示错误。 如果对于要显式装入或自动装入的模块,下列其中一个或多个子例程 loadloadAndInit 子例程将失败:

描述
EACCES 指示该文件不是普通文件,或者程序文件的方式拒绝执行许可权,或者在路径前缀的组件上拒绝搜索许可权。
EINVAL 指示文件或归档成员在其头中具有有效的幻数,但该头已损坏或者对于要运行该文件的机器而言不正确。
ELOOP 指示在转换路径名时迂到过多的符号链接。
ENOEXEC 指示在装入或解析指定模块的符号时发生错误。 这可能是由于尝试装入具有无效 XCOFF 头的模块,未能解析未定义为延迟导入的符号或存在其他几个与装入时间相关的问题。 可以使用 装入查询 子例程来返回有关装入失败的更多信息。 如果使用运行时链接,如果运行时链接器无法解析某些符号,"负荷和 "loadAndInit子程序就会失败。 在此情况下, 错误号 将设置为 ENOEXEC,但 装入查询 子例程将不会返回任何其他信息。
ENOMEM 指示程序需要的内存超过系统施加的最大值所允许的内存量。
ETXTBSY 指示文件当前由某个进程打开以进行写入。
ENAMETOOLONG 指示路径名的组件超过 255 个字符,或者整个路径名超过 1023 个字符。
ENOENT 指示路径前缀的某个组件不存在,或者路径名为空值。 对于 德洛彭 子例程,当尝试打开归档文件中的成员时,不使用 RTLD_MEMBER。
ENOTDIR 指示路径前缀的一个组件不是目录。
ESTALE 指示进程根目录或当前目录位于已卸载的虚拟文件系统中。