原文地址: https://my.oschina.net/yepanl/blog/2222613

看到了一片讲解-fPic选项的文章,讲的还是比较清楚。

在理解PIC概念之前,先了解一下动态链接库的载入时重定位概念。

载入时重定位:

我们知道,Linux的可执行文件一般是elf格式的,在这个可执行文件的头部包含了很多重要的信息:如文件格式,加载地址,符号表等。当连接器链接生成可执行文件时,会将程序的加载地址写入可执行文件头。在程序运行时,动态加载器将可执行文件载入文件头指定的加载地址处,并加载该地址,开始从该地址处运行。由此可见,可执行文件的起始地址是在编译时就决定的:

对于动态库来说,不像静态库(静态库是在链接可执行文件时,代码段和数据段直接拷贝到可执行文件中),是在运行时加载动态库代码,因此无法在编译和链接阶段获取代码段的符号地址(代码段的符号包括引用的全局数据,调用的函数等)。在调用动态库中的函数时,动态加载器动态分配一段进程地址空间,将动态库加载到该地址空间后,再修改代码段的符号地址。至于需要修改的哪些地址,链接器在动态库的文件头中预先写好,供加载器读取修改,动态库的重定位节举例如下:

以上每一项对应着代码段中的一处重定位:在代码段的Offset处,进行Type类型的转换。这就是载入时重定位的基本概念和过程。

载入时重定位的缺点:

(1)动态库的代码段不能在进程间共享:多个进程加载同一个动态库到各自不同的地址空间,导致代码段需要不同的重定位,所以最终每个引用该动态库的进程拥有一份该动态库代码段的不同拷贝。

(2)代码段必须是可写的,增加了被攻击风险。

为了解决载入时重定位的问题,引入了PIC的概念,即位置无关代码。

PIC实现原理:

(1)GOT:在动态库的数据段增加GOT(Global Offset Table),该表的每一项是符号到地址的绝对映射。由于代码段到数据段的偏移是固定的,因此可以在编译时确定代码段中的某个符号到GOT特定项之间的偏移。这样,代码段中的符号偏移就可以在编译时确定了,在加载时也无需修改代码段的内容,只需要填写位于数据段的GOT的所有项的符号的绝对地址就完成了。因为数据段本来就是进程间不共享,每个进程独立的一份,因此GOT的设计完全解决了以上两个问题,从而达到两个目的:1,代码段可以在多进程间共享;2,代码段是只读的。

(2)PLT:PLT是 Program Linkage Table 的缩写,即程序链接表,PLT的出现是为了延时定位的目的。一个动态库中的函数往往要远多于全局变量,并且被调用的函数往往少于定义的函数。GOT中包含了该动态库中的所有的全局变量的映射,并且在连接器加载时解析所有的全局变量的地址。如果用同样的方式去处理函数调用符号,则开销会非常大。因此在代码段设计了一个PLT表,每一项其实是个代码段,用于执行如下逻辑:首次访问时,解析参数和向GOT填写函数地址,后续访问直接访问GOT中的函数地址。如此达到了延时定位的目的。

因此,一个PIC的动态库中,对全局变量使用GOT来映射,对函数调用使用PLT+GOT来映射,从而达到共享库代码段复用,代码段安全访问的目的。而这些就是 PIC 的意义。

关于 gcc/g++编译选项: -fPIC 功能的解释相关推荐

  1. Linux+gcc设置断点,gcc/g++常用编译选项和gdb常用调试命令

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? gcc/g++编译器是我们写编译C/C++程序时离不开的编译工具,而gdb又是调试C/C++程序的利器,这一篇文章我们记 ...

  2. gcc 自动识别的文件扩展名,gcc/g++ -x 选项指定语言,不同 gcc 版本 -std 编译选项支持列表

    对于执行 C 或者 C++ 程序,需要借助 gcc(g++)指令来调用 GCC 编译器. 对于以 .c 为扩展名的文件,GCC 会自动将其视为 C 源代码文件 对于以 .cpp 为扩展名的文件,GCC ...

  3. gcc/g++命令参数中文帮助手册

    引自: http://www.cnblogs.com/liangxiaxu/articles/2617367.html GCC 1 Section: GNU Tools (1) Updated: 20 ...

  4. gcc, g++ - GNU 工程的 C 和 C++ 编译器

    NAME gcc, g++ - GNU 工程的 C 和 C++ 编译器 (egcs-1.1.2)总览 (SYNOPSIS)gcc [ option | filename ]...g++ [ optio ...

  5. gcc g++ 参数介绍

    C和C++ 编译器是集成的.他们都要用四个步骤中的一个或多个处理输入文件: 预处理 (preprocessing),编译(compilation),汇编(assembly)和连接(linking).源 ...

  6. Linux 之 编译器 gcc/g++参数详解

    2016年12月9日16:48:53 ----------------------------- 内容目录: [介绍]  gcc and g++分别是gnu的c & c++编译器 gcc/g+ ...

  7. linux gcc g++编译命令选项

    gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件[预处理器cpp] 2.将预处理后的文件不转换成汇编语言,生成文件.s[编译器egcs] 3.有汇编变为目标代码(机器代码) ...

  8. 【Linux】三、Linux 环境基础及开发工具使用(上篇)|开发工具|编辑器-vim使用|sudo提升权限问题|编译器 - gcc/g++使用|项目自动化构建工构建工具-make/Makefile

    目录 一.开发工具 二.Linux编辑器 - vim使用 2.1 vim 的基本概念 2.2 vim的基本操作 2.3 vim正常模式命令集 2.4 vim末行模式命令集 2.5 简单vim配置 2. ...

  9. 【Linux修炼】6.gcc/g++及Makefile【工具篇】

    每一个不曾起舞的日子,都是对生命的辜负. Linux-gcc/g++及Makefile 本节目标 程序的翻译过程 1.程序的翻译过程 2. 理解选项的含义 3. 动态链接和静态链接 Linux项目自动 ...

最新文章

  1. 匹配替换指定文本为html标签
  2. go reflect的用法
  3. 移动端输入框弹出键盘控制
  4. eclipse上搭建mybatis
  5. 八数码问题II-双向bfs和map标记
  6. 中南大学王斌计算机学院,中南大学 信息科学与工程学院,长沙 410083
  7. 手把手教你学习ROR-6.Rooter的配置
  8. python创建目录保存文件
  9. Varnish——CDN推送平台(web页面批量清除缓存)
  10. IDE安装与配置(2018)
  11. 怎么找网页源文件位置_html网页源代码是什么 如何查看网页源代码经验篇
  12. 配置maven的settings文件
  13. curl myip.ipip.net curl ip.cn curl cip.cc
  14. python spilt()函数
  15. 关于调制比、过调制、基波电压和母线电压的概念和关系总结
  16. 从小白到数据分析师的成长之路
  17. 【原创】VBA学习笔记(15)VBA的参数传递:ByVal 和 ByRef 的区别
  18. 如果想进入IT行业工作,需要做准备吗?
  19. KEIL的hex与bin文件自动生成到指定目录
  20. 索尼电脑安装linux,Sony Vaio P 安装Ubuntu Netbook Remix

热门文章

  1. jieba分词算法总结
  2. 恭喜EDG 夺得冠军
  3. 服务器被腾讯云助手告警通知有木马文件
  4. java 内存 监控_监控JVM内存使用情况
  5. java中使用length获取二维数组的长度
  6. java--for循环执行的顺序
  7. android chrome无法运行,Android 测试 Chrome 浏览器能正常启动 Chrome 浏览器,但是不能进行操作,求大神!!...
  8. Unity手机震动,Unity -> android 震动
  9. 亚马逊精品处理邮件回复
  10. 盘点认证协议 : 普及篇之ADFS , WS-Federation