我已阅读 GCC 的代码生成约定选项,但无法理解“生成与位置无关的代码 (PIC)”的作用。请举一个例子来解释我是什么意思。
原文由 Narek 发布,翻译遵循 CC BY-SA 4.0 许可协议
我已阅读 GCC 的代码生成约定选项,但无法理解“生成与位置无关的代码 (PIC)”的作用。请举一个例子来解释我是什么意思。
原文由 Narek 发布,翻译遵循 CC BY-SA 4.0 许可协议
在加载库时或在运行时解析动态库中函数的链接。因此,程序运行时,可执行文件和动态库都会被加载到内存中。加载动态库的内存地址无法提前确定,因为固定地址可能与另一个需要相同地址的动态库发生冲突。
有两种常用的方法来处理这个问题:
1.搬迁。如有必要,修改代码中的所有指针和地址以适合实际加载地址。重定位由链接器和加载器完成。
2.位置无关代码。代码中的所有地址都是相对于当前位置的。默认情况下,类 Unix 系统中的共享对象使用与位置无关的代码。如果程序运行很长时间,特别是在 32 位模式下,这比重定位效率低。
“ 位置无关代码”这个名称实际上意味着以下内容:
代码段不包含需要重定位的绝对地址,而只有自身相对地址。因此,代码段可以加载到任意内存地址并在多个进程之间共享。
数据部分不在多个进程之间共享,因为它通常包含可写数据。因此,数据部分可能包含需要重定位的指针或地址。
所有公共功能和公共数据都可以在 Linux 中被覆盖。如果 main 可执行文件中的函数与共享对象中的函数同名,则 main 中的版本将优先,不仅在从 main 调用时,而且从共享对象调用时也是如此。同样,当 main 中的全局变量与共享对象中的全局变量同名时,即使从共享对象访问,也会使用 main 中的实例。这种所谓的符号插入旨在模仿静态库的行为。
共享对象有一个指向其函数的指针表,称为过程链接表 (PLT),以及一个指向其变量的指针表,称为全局偏移表 (GOT),以实现此“覆盖”功能。
所有对函数和公共变量的访问都通过这些表。
ps 在无法避免动态链接的情况下,有多种方法可以避免位置无关代码的耗时特性。
您可以从这篇文章中了解更多信息: http ://www.agner.org/optimize/optimizing_cpp.pdf
原文由 Konstantin Burlachenko 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.5k 阅读
3 回答485 阅读✓ 已解决
位置无关代码意味着生成的机器代码不依赖于位于特定地址才能工作。
例如,跳跃将产生为相对而非绝对。
伪组装:
PIC:无论代码是在地址 100 还是 1000,这都会起作用
非 PIC:仅当代码位于地址 100 时才有效
编辑:回应评论。
如果您的代码是使用 -fPIC 编译的,则它适合包含在库中 - 库必须能够从内存中的首选位置重定位到另一个地址,在您的库喜欢的地址处可能有另一个已加载的库。