我对与位置无关的代码及其在动态库中的使用感到非常困惑。
我发现了这个关于 GCC 的 -fPIC 选项的好例子:GCC -fPIC 选项 ,我弄清楚了它是如何工作的。
但是,我很难理解为什么动态库需要独立于特定地址的代码。加载动态库时,为什么我们不能只保存其绝对地址(例如库中函数的地址)并使用它们?为什么在这种情况下必须使用相对地址?
用“gcc main.c”编译的简单程序int main() { return 0; }
总是依赖于位置?
我对与位置无关的代码及其在动态库中的使用感到非常困惑。
我发现了这个关于 GCC 的 -fPIC 选项的好例子:GCC -fPIC 选项 ,我弄清楚了它是如何工作的。
但是,我很难理解为什么动态库需要独立于特定地址的代码。加载动态库时,为什么我们不能只保存其绝对地址(例如库中函数的地址)并使用它们?为什么在这种情况下必须使用相对地址?
用“gcc main.c”编译的简单程序int main() { return 0; }
总是依赖于位置?
-fPIC
绝不是共享库问题的唯一解决方案。在 ELF Linux 之前使用a.out 可执行格式。在a.out
所有共享库中,都在全局地址空间中使用了唯一地址,因此它们总是被所有进程加载到相同的固定地址。事实证明,这非常难以管理:所有发行版包必须在彼此之间达成一致,为哪个库保留哪个地址范围,并且随着库随着时间的推移不断修改该协议。
-fPIC
让我们摆脱了这个混乱。
根据您的建议,所有进程的地址范围的全局动态保留,一旦某个进程在某个内存区域映射了一个库,即使它从未实际加载该库,其他进程也无法重用该区域。对于具有 4G 地址空间的 32 位系统(甚至 2G 是为内核保留的上层 2G),这可能会很快耗尽 VM。另一个问题来自这样一个事实,即主可执行文件的大小因进程而异,因此没有可以安全加载库的全局起始地址。