【发布时间】:2013-06-03 10:05:16
【问题描述】:
在 32 位系统中,每个进程实际上都有 2^32 字节的连续地址空间。那么为什么链接器生成的最终可执行代码需要可重定位。有什么要求,因为生成的所有地址都是进程自己地址空间中的虚拟地址,而其他进程不能使用相同的地址。 因此,该过程可以放置在它想要的任何地方。为什么要重定位?
【问题讨论】:
标签: c linker operating-system loader virtual-memory
在 32 位系统中,每个进程实际上都有 2^32 字节的连续地址空间。那么为什么链接器生成的最终可执行代码需要可重定位。有什么要求,因为生成的所有地址都是进程自己地址空间中的虚拟地址,而其他进程不能使用相同的地址。 因此,该过程可以放置在它想要的任何地方。为什么要重定位?
【问题讨论】:
标签: c linker operating-system loader virtual-memory
可执行代码并不总是包含相对地址。例如,在 Windows 上,寻址通常是绝对的(例如,对于全局数据)。
考虑两个不同的动态库。两者都是针对 0x00100000 的固定基地址编译的。您的程序尝试加载它们。放置第二个 DLL 的加载器在哪里?它的首选基地址已被其他 DLL 使用。
在这种情况下,可重定位代码有助于将第二个 DLL 放置在不同的地址,并将其内部指针修补到新位置。使用固定的基地址,加载第二个 DLL 就会失败。
【讨论】:
一些操作系统使可执行代码可重定位(这绝对不是所有操作系统都通用的)以允许address space layout randomization。这有助于缓解某些攻击。
过去,当堆栈可执行时,可以通过直接在溢出的堆栈或堆上编写可执行代码来利用缓冲区溢出。随着操作系统变得更加智能并开始阻止堆栈和堆的执行,攻击变得更加复杂并开始通过执行return oriented programming 使用内存中的已知代码序列。对这类攻击的缓解首先是通过随机化共享库的内存布局(因为它们更容易被利用),然后当攻击者切换到攻击主可执行文件时,通过随机化可执行文件的内存位置来完成。为了使它成为可能,主要的可执行文件需要是可重定位的。
【讨论】:
它需要是可重定位的,因为为了执行您的进程需要放入就绪队列中的实际主内存中。现在它应该放置在主存储器中的位置不是固定的(它放置在有足够空间的地方),因此指令的实际地址与其虚拟地址不同。
因此,调用函数、返回等的语句需要相应地更新,指向这些函数的实际地址
【讨论】: