5

我想知道在具有虚拟内存支持的系统上加载时重定位实际上意味着什么。我在想,在具有虚拟内存的系统中,每个可执行文件的地址都从零开始,并且在运行时地址将使用转换为物理地址页表。因此可执行文件可以加载到内存中的任何位置,而无需任何重定位。然而这篇关于共享库的文章提到链接器在可执行文件中指定了一个地址,可执行文件将被加载(入口点地址)。

http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries/

还有很多关于动态链接的文章谈论绝对地址。我的理解错了吗?

4

1 回答 1

17

加载时重定位和虚拟内存支持是两个不同的概念。如今,几乎所有 CPU 和操作系统都支持虚拟内存。关于虚拟内存,唯一真正重要的一点是:忘记物理地址。现在这是硬件和操作系统的责任,除非您正在编写分页系统,否则您可以忘记物理地址。程序使用的所有地址都是虚拟地址。这是一个巨大的优势,并且极大地简化了编程模型。在 32 位系统上,这仅仅意味着每个进程都有自己的 4 GiB 内存空间,范围0x000000000xffffffff.

An.exe代表一个过程。链接器.exe.obj文件中生成。虽然两者都是二进制文件,但.obj文件不可执行,因为它们不包含所有变量和函数的地址。链接器的工作是提供这些地址,它通过将这些.obj文件端到端放置然后计算所有符号(函数和变量)的确切地址来确定。因此,.exe所创建的函数和变量的每个地址都“硬编码”到其中。但是在创建之前仍然需要一个关键信息.exe。链接器必须了解将在内存.exe中加载的位置。是在地址0x00000000还是在0xffff0000, 或者别的地方?例如,在 Windows 中,所有.exes 总是在绝对起始地址0x00400000. 这称为基地址。当链接器生成符号(函数和变量)的最终地址时,它会从该地址开始计算这些地址。

现在,.exes 很少需要在任何其他地址加载。但对于.dlls 来说,情况并非如此。.ddls 与 s 相同.exe(两者都被格式化为可移植可执行 (PE) 文件格式,它描述了内存布局,例如,文本到哪里、数据到哪里以及如何找到哪一个)。.dlls 也有一个首选地址。这仅仅意味着链接器在计算.dll. 如果.dll在这个地址加载,那么我们就都设置好了。

但是,如果由于已经在该地址加载了其他一些空间而.dll无法在该地址加载(比如说它是0x10000000) ,那么加载器将在内存中找到一些其他空间并加载那里。但是,现在函数和符号的全局地址不正确。因此,加载程序必须进行重定位(也称为“修复”),其中它调整所有全局符号和函数的地址以反映它们的实际地址。.dll.dll.dll

为了进行这种调整,加载程序需要能够在.dll. PE 文件有一个.reloc部分包含所有此类符号的内部偏移量。

当然,还有其他细节,例如,关于在编译器生成代码时如何使用间接调用,以便调用是间接调用,而不是直接调用,并且可以通过.exe.

最后,要点是:当代码未在预期的位置(在 4 GiB 地址空间内)加载时,您需要重定位(某种)来调整调用和跳转中的地址以及变量访问指令加载。当操作系统加载 a.exe时,它必须在这个 4 GiB 地址空间中选择一个合适的位置,它将代码和数据块从这里复制到.exe磁盘上。

于 2012-01-14T02:34:54.780 回答