加载时间重定位和虚拟内存

时间:2011-08-25 16:24:14

标签: linker loader dynamic-linking dynamic-loading

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

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

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

1 个答案:

答案 0 :(得分:9)

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

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

现在,.exe很少需要在任何其他地址加载。但.dll的情况并非如此。 .ddl.exe s相同(两者都以便携式可执行(PE)文件格式格式化,它描述了内存布局,例如,文本在哪里,数据在哪里,以及如何找到哪一个)。 .dll也有首选地址。这只是意味着链接器在计算.dll内符号的地址时使用此值。如果在此地址加载.dll,那么我们都已设置好。

但是如果.dll无法加载到这个地址(比如它是0x10000000),因为其他.dll已经加载到这个地址,那么加载器会找到其他的内存中的空间并加载.dll。但是,.dll中的函数和符号的全局地址现在不正确。因此,加载器必须执行重定位(也称为“fixup”),在其中调整所有全局符号和函数的地址以反映其实际地址。

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

当然,还有其他细节,例如,关于在编译器生成代码时如何使用间接,以便调用是间接的,而不是直接调用,并且通过头中的已知内存位置访问变量.exe

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