DSO(dynamic shared object)动态共享对象的原理

原创 2013年12月02日 10:40:22


摘要:可执行ELF文件的生成,如果从源文件c开始算起,需要经过编译、链接、装载几个步骤。在链接和装载这两个步骤中,有两种不同的实现方式,一种是静态链接,这样加载之前,已经形成可执行目标文件;另外一种是动态链接,这种模式下,链接阶段只是链接一部分目标文件,动态链接库(DSO)在装载的时刻才会映射到进程地址空间。本文主要讲解DSO的原理。


1.装载过程涉及的问题

当程序被装载时,系统的动态链接器会将程序所需的所有动态链接库(例如最基本的libc.so)装载到进程的地址空间,且将程序中所有为决议的符号绑定到相应的动态链接库中,并进行重定位工作(术语叫装载时重定位-load time relocation,在windows中,又叫基址重置-rebasing,区别于静态链接的链接时重定位-link time relocation)。也即,动态链接是把可执行elf的形成过程从本来的程序链接前推迟到装载时。共享对象的最终装载地址在编译时是不确定的,而是在装载时,装载器根据当前地址空间的空闲情况,动态分配一块足够大小的虚拟地址空间给相应的共享对象。        

        装载时重定位的问题:so文件被load并映射至虚拟空间后,指令部分通常是多个进程间共享的,通常的装载时重定位是通过修改指令实现的(主要是根据情况修改指令中涉及到的地址),所以无法做到同一份指令被多个进程共享(因为指令被重定位后对每个进程来讲是不同的)。这样一来,就失去了动态链接节省memory的一大优势。

         为解决此问题,引入了地址无关代码(PIC,Position-independent Code,详细概念见wikipedia)的技术,基本思路是把指令中那些需要被修改的部分分离出来,跟数据部分放到一起,这样,剩下的指令就可以保持不变,而数据部分在每个进程中拥有一个副本。ELF针对各种可能的访问类型(模块内部指令调用、模块内部数据访问、模块间指令调用、模块间数据访问),实现了对应地址引用方式,从而实现了PIC。

        对应到实际应用中,我们可以在编译时指定-fPIC参数让gcc产生地址无关码。


2.印象动态链接性能的因素


        a. 与静态链接相比,动态链接对全局和静态的数据访问都要进行GOT(Global Offset Table,实现PIC时引入的具体技术)定位,然后间接寻址;对于模块间的调用也要先定位GOT,然后间接跳转,如此,程序的运行速度就会减慢

       b. 程序装载时,动态链接器要进行一次链接工作,即查找并装载所需的共享对象,然后进行符号查找、地址重定位等工作,这会减慢程序启动速度

       一方面,程序模块往往包含了大量的函数调用,从而导致动态链接器在模块间函数引用的符号查找及重定位方面耗费时间;另一方面很多函数并不会在程序运行初期就用到(尤其是有些异常处理函数),由此,EFL采用延迟绑定(lazy binding)来对动态链接做优化,其基本思想是当函数第一次被调用时才进行绑定(符号查找、重定位等),若没有被调用则不进行绑定。这个思路可以大大加快程序启动速度,对于有大量函数引用的程序启动时,尤为明显。具体到实现,EFL采用PLT(procedure linkage table)来实现,具体过程很是精妙复杂,本文只是抛砖引玉,不再详述,有兴趣的同学可以用PLT英文关键字google相关资料



3.疑问

1)是否能够用地址映射共享DSO内存

同一份指令应当是指的共享模块中的指令吧?如果是的话,那么各个进程无论将共享模块装载至进程虚拟地址空间的何处,只要在该进程装载时对共享模块中地址的引用执行重定位,即使装载的地址不一样,重定位之后也是各个进程的中的代码对共享模块引用地址的不同,而共享模块中的代码是不需要变化的?


分析:简而言之,DSO是不是可以不修改代码,而是通过将不同进程的虚拟地址映射到同一个区域的物理地址来实现,DSO的共享?


不要忘了,装载进去的都是指令,也就是一行行的“汇编代码”:

mov eax, [0x123456]

很显然,如果DSO引用了外部模块的地址,那么这个地址的变量值总是随着整个进程空间布局的不同而变化。那么,这个问题就不是能用linux内核的内存管理中虚实地址的映射能够解决的了。

Java.text包学习笔记

一 java.text包概述: Java API中对java.text包的描述为:   提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。这意味着所编写的主程序或 applet 是...

java.util.zip包在解压缩文件方面入门使用

java.util.zip包在解压缩文件方面入门使用

Linux 动态链接库(shared object)的基础知识

动态链接库的就基础知识 库有两种:动态和静态;动态是以.so 为后缀,静态是以.a为后缀;比如:libhello.o  libhello.a 静态库是在写代码时调用的库函数,代码中调用库函数,...

静态库(Archive Libraries)和动态库(Shared Object)的基本知识

linux下编译,常会遇到后缀为:.o .so .a .la .ko等格式文件,尽管linux并不以扩展名作为识别文件格式的唯一依据,但规范约定还是有的,如下: .o 是目标对象文件,相当于wind...

aix中使用xlc编译生成动态链接库(shared object)(.so)文件的方法

今天写一个ppt的时候,忽然发现不会用xlc编译成出.so文件,于是baidu,未果。 后cc看了一些命令的选项后,查到了编译的选项 。 假设我有hellofirst.c和hellosecond....

Json.net实现方便的Json转C#(dynamic动态类型)对象

以前需要将一段json字符串转换为C#对象时,一般都是定义一个与之对应的实体类来接收。这样做有一个很大的缺点,就是当字符串特别长,属性特别多,又有嵌套时,手敲这个实体类就非常痛苦。     比如之前...

MFC动态创建(dynamic creation)实现原理

在用到MFC的文档视图构架你可能有个非常迷惑的地方.就是很多类不知道在哪里就被莫名其妙的实例化了. 以单文档视图为例.代码中你能看到的的实例化的地方就只有两个一个是CWinApp的一个全局变量的实例...

redis 数据结构之和对象---简单动态字符串SDS(simple dynamic string)

1.介绍: reids 没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组)而是构建了一种名为简单动态字符串的抽象类型,并为redis的默认字符串表示,因为C字符串不能满足redis对字符串...
  • i_bruce
  • i_bruce
  • 2014年11月08日 16:19
  • 796

mfc动态创建(dynamic create)实现原理

在用到MFC的文档视图构架你可能有个非常迷惑的地方.就是很多类不知道在哪里就被莫名其妙的实例化了. 以单文档视图为例.代码中你能看到的的实例化的地方就只有两个一个是CWinApp的一个全局变量的...

C++对象动态生成(Dynamic Create)的简单实现

以前一直是C++的coder,最近由于到了另一家公司,因此开始写java项目,相信C++的程序员都会对java语言原生支持的动态生成很是羡慕,但是C++不支持反射(reflection),也就无法根据...
  • torytin
  • torytin
  • 2012年05月11日 17:17
  • 5300
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:DSO(dynamic shared object)动态共享对象的原理
举报原因:
原因补充:

(最多只允许输入30个字)