哪些类型的文件可以动态加载?

哪些类型的文件可以动态加载?

操作系统概念,作者:Silberschatz A.、Galvin PB、Gagne G. - 操作系统概念,第 9 版 - 2012 年说

8.1.4 动态加载

在我们到目前为止的讨论中,进程的整个程序和所有数据都必须位于物理内存中才能执行。因此,进程的大小受到物理内存大小的限制。为了获得更好的内存空间利用率,我们可以使用动态加载。通过动态加载,例程在被调用之前不会被加载。 所有例程都以可重定位加载格式保存在磁盘上。主程序被加载到内存中并被执行。当一个例程需要调用另一个例程时,调用例程首先检查另一个例程是否已加载。如果没有,则调用可重定位链接加载器将所需的例程加载到内存中并更新程序的地址表以反映此更改。然后控制权被传递给新加载的例程。

动态加载的优点是例程仅在需要时才加载。当需要大量代码来处理不经常发生的情况(例如错误例程)时,此方法特别有用。在这种情况下,尽管总程序大小可能很大,但使用(并因此加载)的部分可能要小得多。

动态加载不需要操作系统的特殊支持。用户有责任设计他们的程序以利用这种方法。然而,操作系统可以通过提供库例程来实现动态加载来帮助程序员。

8.1.5 动态链接和共享库

Linux 中哪些类型的文件具有“可重定位加载格式”,

  • ELF可执行文件,
  • .so 共享库文件,
  • 一个内核模块,
  • .o 目标文件?

它们都可以动态加载吗?

引用中的“可重定位加载格式”是否意味着 .o 目标文件、内核模块,而不是 .so 共享库文件,根据:

本书直到第 8.1.5 节才提到任何有关共享库的内容,因此在我看来,第 8.1.4 节动态加载不一定将共享库加载到用户程序中,但可能会加载其他内容。真的吗?

8.1.4节的最后一段似乎说程序员需要显式地执行动态加载。它指的是吗 dlopen()?哪些类型的 ELF 文件可以dlopen() 接受作为其第一个参数:.so 共享库、.o 目标文件、内核模块、可执行 ELF 文件?

谢谢。

答案1

共享库实际上并不需要可重定位。 AT&T 于 1987 年左右在 SYSvr3 中使用了不可重定位共享库。

AT&T 使用的方法基于共享库中的固定地址,并且共享库在启动时由特殊的系统工具安装在系统内存中(任何进程都可以使用)。使用此类库的程序已与安装时使用的固定地址进行链接。这种方法非常有限,因为需要一个全局管理员来定义各种库的加载地址。

今天使用的方法基于 Sun Microsystems 1987 年的研究,并于 1987 年 12 月发布。

它基于mmap()内核中的设施。每个程序都包含特殊的启动代码,用于映射使用可重定位代码的所需库。

每个库都包含一个特殊的表,其中包含库中各种符号的偏移量。每个程序都包含一个包含函数名称的表,并且二进制文件对与所需的所有函数相关的表条目执行跳转子例程。

该表条目包含一条指向运行时链接器代码的跳转指令,当第一次使用它时,运行时链接器会通过跳转到共享库中的函数来替换该跳转。

所有这些都是由系统软件处理的,而不是用户程序设计的主题。

顺便说一句:这本书声称没有程序可以变得比物理内存更大。这在 20 世纪 60 年代确实如此。 IBM 在 20 世纪 70 年代初对其大型机进行了更改,BSD 在 1979 年通过虚拟内存管理对 UNIX 进行了更改。

dlopen()可用于在运行时“手动”加载动态库,从而允许依赖于之前发生的情况。例如,声音播放程序在发现文件参数引用使用编码的声音文件后可以决定使用dlopen加载解码器。mp3mp3

如果您使用dlopen,则不会自动链接到加载的共享库中的函数。您需要使用dlsym()从函数名称获取地址,然后通过指针取消引用来调用该函数。

您不能dlopen创建文件.o,因为需要创建文件,_PROCEDURE_LINKAGE_TABLE_并且该文件是由创建文件所需的特殊链接过程创建的.so.

Microsoft 使用的方法源自基于dlopen.然而,Microsoft 会自动创建代码,其工作方式与您手动使用dlopen.相关代码位于与所谓的同名的静态库内dll。该静态库静态链接到程序,并包含加载该库、检索函数地址然后调用函数指针的 trmapolin 代码。

Microsoft 编译器始终创建可重定位代码,因此即使使用该编译器编译的完全静态库也使用可重定位代码。

在一般情况下,例程在被引用之前不会加载的说法是错误的,它仅适用于这种dlopen情况。

由 ELF 运行时系统管理的库可以通过 列出ldd,而手动管理的库则dlopen无法列出,因为它们的名称可能是运行时字符串处理的结果。

相关内容