在Linux系统中,动态链接文件称为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象,一般是以.so为扩展名的文件。在Windows系统中,则称为动态链接库(Dynamic Linking Library),很多以.dll为扩展名。这里只备忘Linux的共享对象。
在实现一共享对象时,最一般的编译链接命令行为
 g++ -fPIC -shared test.cc -o lib.so

或者是:

 g++ -fPIC test.cpp -c -o test.o
ld -shared test.o -o lib.so
上面的命令行中-shared表明产生共享库,而-fPIC则表明使用地址无关代码。PIC:Position Independent Code. Linux下编译共享库时,必须加上-fPIC参数,否则在链接时会有错误提示(有资料说AMD64的机器才会出现这种错误,但我在Inter的机器上也出现了):
/usr/bin/ld: test.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
test.o: could not read symbols: Bad value
collect2: ld returned exit status

如何确认一个共享对象是PIC呢?

readelf -d foo.so |grep TEXTREL 
如果上边的shell有任何输出,则说明这foo.so不是PIC。TEXTREL表示代码段重定位表地址,PIC的共享对象不会包含任何代码段重定位表。
fPIC的目的是什么?共享对象可能会被不同的进程加载到不同的位置上,如果共享对象中的指令使用了绝对地址、外部模块地址,那么在共享对象被加载时就必须根据相关模块的加载位置对这个地址做调整,也就是修改这些地址,让它在对应进程中能正确访问,而被修改到的段就不能实现多进程共享一份物理内存,它们在每个进程中都必须有一份物理内存的拷贝。fPIC指令就是为了让使用到同一个共享对象的多个进程能尽可能多的共享物理内存,它背后把那些涉及到绝对地址、外部模块地址访问的地方都抽离出来,保证代码段的内容可以多进程相同,实现共享。
抽离出这部分特殊的指令、地址之后,放到了一个叫做GOT(Global Offset Table)的地方,它放在数据段中,每一个进程都有独立的一份,里面的内容可能是变量的地址、函数的地址,不同进程它的内容很可能是不同的,这部分就是被隔离开的“地址相关”内容。模块被加载的时候,会把GOT表的内容填充好(在没有延迟绑定的情况下)。代码段要访问到GOT时,通过类似于window的call/pop/sub指令得到GOT对应项的地址。
对于模块中全局变量的访问,为了解决可执行文件跟模块可能拥有同一个全局变量的问题(此时,模块内的全局变量会被覆盖为可执行文件中的全局变量),对模块中的全局变量访问也通过GOT间接访问。
这样子,每一次访问全局变量、外部函数都需要去计算在GOT中的位置,然后再通过对应项的值访问变量、调用函数。从运行性能上来说,比装载时重定位要差点。装载时重定位就是不使用fPIC参数,代码段需要一个重定位表,在装载时修正所有特殊地址,以后运行时不需要再有GOT位置计算和间接访问。(但是,我在自己机子上测试,编译链接共享库时,没法不使用fPIC参数,可能多数系统都要求必须有fPIC)
如果在装载时就去计算GOT的内容,那么会影响加载速度,于是就有了延迟绑定(Lazy Binding),直到用时才去填充GOT。它使用到了PLT(Procedure Linkage Table):每一项都是一小段代码,对应于本运行模块要引用的函数。函数调用时,先到这里,然后再到GOT。在函数第一次被调用时,进入PLT跳到加载器,加载器计算函数的真正地址,然后将地址写入GOT对应项,以后的调用就直接从PLT跳到GOT记录的函数位置。这样也减少了运行时多次调用多次计算GOT位置。
PIC的共享对象也会有重定位表,数据段中的GOT、数据的绝对地址引用,这些都是需要重定位的。
 readelf -r Lib.so

可以看到共享对象的重定位表,.rel.dyn是对数据引用的修正,.rel.plt是对函数引用的修正。

Linux共享对象之编译参数 -fPIC的更多相关文章

  1. Linux共享对象之编译参数fPIC

    最近在看Linux编程的基础知识,打算对一些比较有趣的知识做一些汇总备忘,本文围绕fPIC展开,学习参考见文末. 在Linux系统中,动态链接文件称为动态共享对象(DSO,Dynamic Shared ...

  2. Linux共享对象之编译参数fPIC(转)

    最近在看Linux编程的基础知识,打算对一些比较有趣的知识做一些汇总备忘,本文围绕fPIC展开,学习参考见文末. 在Linux系统中,动态链接文件称为动态共享对象(DSO,Dynamic Shared ...

  3. 软件自带依赖库还是共享对象库/为什么linux发行版之间不能有一个统一的二进制软件包标准

    接前文:Linux软件包(源码包和二进制包)及其区别和特点 在前文,我们知道了linux软件包分为源码包和二进制包两种方式,而不同的发行版之间又有着自己的二进制打包格式. 首先,软件运行依赖着各种各样 ...

  4. gcc编译参数-fPIC的一些问题

    gcc编译参数-fPIC的一些问题 (2012-07-26 15:41:08) 转载▼ 标签: linux compiler gcc -fpic it 分类: NSN_BspDriver ppc_85 ...

  5. Linux共享库、静态库、动态库详解

    1. 介绍 使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用.程序函数库 ...

  6. Linux共享库两种加载方式简述

      Linux共享库两种加载方式简述  动态库技术通常能减少程序的大小,节省空间,提高效率,具有很高的灵活性,对于升级软件版本也更加容易.与静态库不同,动态库里面的函数不是执行程序本身 的一部分,而是 ...

  7. gcc编译参数-fPIC问题 `a local symbol' can not be used when making a shared object;

    gcc -shared -o hack.so hack.c/usr/bin/ld: /tmp/ccUZREwA.o: relocation R_X86_64_32 against `a local s ...

  8. linux 共享内存shm_open实现进程间大数据交互

    linux 共享内存shm_open实现进程间大数据交互 read.c #include <sys/types.h> #include <sys/stat.h> #includ ...

  9. Flash本地共享对象 SharedObject

    以下内容是对网上一些资料的总结 Flex SharedObject 介绍(转自http://www.eb163.com/club/thread-3235-1-1.html): Flash的本地共享对象 ...

随机推荐

  1. C#中的BackgroundWorker控件

    C#中的BackgroundWorker控件   Keywords: C# .NET BackgroundWorkerSource: http://txw1958.cnblogs.com/ Backg ...

  2. 分布式事务_01_2PC框架raincat快速体验

    一.前言 关于2PC的理论知识请见:分布式_理论_03_2PC 这一节我们来看下github上一个优秀的2PC分布式事务开源框架的快速体验. 二.源码 源码请见: https://github.com ...

  3. 分布式_事务_02_2PC框架raincat源码解析

    一.前言 上一节已经将raincat demo工程运行起来了,这一节来分析下raincat的源码 二.协调者启动过程 主要就是在启动类中通过如下代码来启动 netty nettyService.sta ...

  4. Mybatis_总结_03_用_动态SQL

    一.前言 MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空格,还 ...

  5. spring MVC multipart处理文件上传

    在开发Web应用程序时比较常见的功能之一,就是允许用户利用multipart请求将本地文件上传到服务器,而这正是Grails的坚固基石——Spring MVC其中的一个优势.Spring通过对Serv ...

  6. linux下配置cvs服务器以及cvs常用命令

    .查看系统是否安装有cvs #cat /etc/services | grep cvspserver 看看是否有: cvspserver /tcp #CVS client/server operati ...

  7. 基于RTP协议的H.264传输

    1.  引言        随 着信息产业的发展,人们对信息资源的要求已经逐渐由文字和图片过渡到音频和视频,并越来越强调获取资源的实时性和互动性.但人们又面临着另外一种不可避免 的尴尬,就是在网络上看 ...

  8. 程序员如何编写好开发技术文档 如何编写优质的API文档工作

    编写技术文档,是令众多开发者望而生畏的任务之一.它本身是一件费时费力才能做好的工作.可是大多数时候,人们却总是想抄抄捷径,这样做的结果往往非常令人遗憾的,因为优质的技术文档是决定你的项目是否引人关注的 ...

  9. CF Round 542 Div1.

    B. Wrong Answer 构造一个长度为 2000 的数组,满足最大“子段和 $\times$ 子段长度”比最大子段和刚好大 k sol: 一个比较好的构造方法: 令数组总和为 $S$,然后构造 ...

  10. Qt之事件处理机制

    思维导读 一.事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下 ...