vja*_*n27 2 linker loader dynamic-linking dynamic-loading
我想知道在具有虚拟内存支持的系统上实际意味着什么是加载时重定位.我认为在具有虚拟内存的系统中,每个可执行文件都将具有从零开始的地址,并且在运行时,地址将被转换为物理地址使用因此,可执行文件可以加载到内存中的任何位置,而无需任何重定位.但是,有关共享库的这篇文章提到链接器指定可执行文件中要加载可执行文件的地址(入口点地址).
http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries/
还有许多关于动态链接的文章谈论绝对地址.我的理解错了吗?
小智 9
加载时重定位和虚拟内存支持是两个不同的概念.如今几乎所有的CPU和操作系统都支持虚拟内存.了解虚拟内存的唯一非常重要的一点是:忘记物理地址.这是硬件和操作系统的责任,除非您正在编写分页系统,否则您可以忘记物理地址.程序使用的所有地址都是虚拟地址.这是一个巨大的优势,并极大地简化了编程模型.在32位的系统,这仅仅意味着每个进程获取它自己的4吉布存储器空间,从0x00000000到0xffffffff.
An .exe代表一个过程.链接器.exe从.obj文件生成.虽然两者都是二进制文件,但.obj文件不可执行,因为它们不包含所有变量和函数的地址.链接器的工作是提供这些地址,它通过.obj端到端地放置这些文件然后计算所有符号(函数和变量)的确切地址来确定.因此,.exe创建的函数和变量的每个地址都被"硬编码"到其中.但是.exe在创建之前还需要一个关键信息.链接器必须具有关于.exe将加载内存的位置的内部知识.它会在地址0x00000000,或在0xffff0000其他地方吗?例如,在Windows中,所有.exes总是以绝对起始地址加载0x00400000.这称为基地址.当链接器生成符号(函数和变量)的最终地址时,它将从此地址开始计算.
现在,.exe很少需要在任何其他地址加载.但对于.dlls 来说,情况并非如此..ddls与.exes 相同(两者都以便携式可执行(PE)文件格式格式化,它描述了内存布局,例如,文本去哪里,数据去哪里,以及如何找到哪一个)..dlls也有一个首选的地址.这只是意味着链接器在计算内部符号的地址时使用此值.dll.如果.dll在此地址加载,那么我们都已设置好.
但是如果.dll无法加载到这个地址(比如说是0x10000000),因为其他一些.dll已经加载到这个地址,那么加载器会在内存中找到一些其他的空间并加载.dll它.但是,.dll现在函数和符号的全局地址不正确.因此,加载器必须进行重定位(也称为"修正"),其中它调整所有全局符号和函数的地址以反映它们的实际地址.
为了进行这种调整,加载器需要能够找到所有这些符号.dll.PE文件的.reloc部分包含所有此类符号的内部偏移量.
当然,还有其他细节,例如,关于在编译器生成代码时如何使用间接,以便不是直接调用,而是调用间接调用,并且通过标头中的已知内存位置访问变量.exe.
最后,要点是这样的:当代码没有加载到预期的位置(在4 GiB地址空间内)时,你需要重新定位(某种类型)调整调用中的地址和跳转以及变量访问指令加载.当操作系统加载a时.exe,它必须在这个4 GiB地址空间中选择一个合适的位置,它将从.exe磁盘上复制代码和数据块.