PIC通过相对寻址和GOT/PLT机制实现代码在任意内存地址运行,确保共享库支持ASLR并可被多个进程安全共享。

地址无关代码(Position Independent Code,简称 PIC)是 C++(以及 C)编译时生成的一种特殊机器码,它不依赖于程序加载到内存中的具体地址。这种特性对于动态库(共享对象)至关重要,因为多个程序可能同时加载同一个共享库,而系统无法保证每次都将库加载到相同的内存地址。
PIC 是如何工作的?
PIC 的核心思想是避免使用绝对地址引用,转而采用相对寻址方式。在 x86-64 架构中,大多数指令支持 RIP 相对寻址(RIP 是指令指针寄存器),这意味着代码可以基于当前指令的位置来访问数据或跳转函数,而不是硬编码一个固定地址。
例如,当共享库中需要访问一个全局变量或调用另一个函数时,编译器不会直接写入该变量的绝对地址,而是通过全局偏移表(GOT, Global Offset Table)和过程链接表(PLT, Procedure Linkage Table)间接访问。
GOT:存储外部变量和函数的实际运行时地址,由动态链接器在加载时填充。 PLT:用于延迟绑定(lazy binding)外部函数调用,第一次调用时解析地址,后续直接跳转。
这样,无论共享库被加载到哪个内存位置,只要 GOT 和 PLT 被正确设置,代码都能正常运行。
立即学习“C++免费学习笔记(深入)”;
为什么动态库必须使用 PIC?
现代操作系统使用 ASLR(Address Space Layout Randomization)安全机制,随机化程序和库的加载地址以防止攻击。如果动态库不是 PIC,它只能加载到预定地址,一旦地址冲突或被占用,就会导致加载失败。
使用 PIC 后,共享库可以在任意地址加载,提高了兼容性和安全性。Linux 上的 .so 文件(共享对象)通常要求使用 -fPIC 编译选项生成真正的地址无关代码。
不带 -fPIC 编译的代码可能仍能在某些情况下工作,但在 64 位系统上链接为共享库时常会报错。 -fPIC 会对性能有轻微影响(间接访问增加开销),但现代 CPU 缓存机制已大幅缓解这一问题。
共享对象的加载与符号解析
当你编译一个 C++ 共享库:
g++ -fPIC -shared -o libmylib.so mylib.cpp
编译器会生成 PIC 指令,并构建包含代码段、数据段、GOT/PLT 等结构的 ELF 共享对象文件。
运行程序时,动态链接器(如 /lib64/ld-linux-x86-64.so)负责:
将共享库映射到进程地址空间的可用区域。 解析外部符号并填充 GOT 表项。 处理重定位信息,修正需要调整的地址引用。
多个进程可以共享同一份共享库的代码段(只读),但每个进程拥有独立的数据段副本(包括 GOT),确保变量隔离。
基本上就这些。PIC 是实现高效、安全共享库的基础技术,理解它有助于写出更可靠、可移植的 C++ 动态库代码。
以上就是c++++的地址无关代码(PIC)是什么_c++动态库与共享对象原理的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1487828.html
微信扫一扫
支付宝扫一扫