为什么要使用动态链接?

  在现代的linux系统中,假设一个普通的程序会使用到c语言静态库至少1MB以上,那么,如果我们的机器运行100个这样的程序,就用浪费近100MB的内存;如果磁盘有2000个这样的程序,就要浪费2GB的内存。

  静态链接对程序的更新、发布等也会带来问题。比如程序program1使用由第三方厂家提供的库lib.o,当厂家更新lib.o时,程序program1的厂商必须先得到lib.o,那后将program1重新链接,并将整个新的program1发布给客户。可以想象,如果一个这个程序很大,这是多么耗费时间的事。

  动态链接正是为了解决静态链接而出现的一种技术。它的优点是:共享的目标文件在磁盘中只有一个副本,在内存中的代码段只有一个副本(通过文件内存映射来实现),这样不仅节约了内存空间,还可以减少物理页面的换进换出;可以动态更换某个模块而不需要重新编译整个程序,不过要重新启动程序才行。这样使得程序升级很方便。

动态链接的基本思想

  动态链接的基本思想就是把程序模块拆分成几个相对独立的部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不像静态链接把所有程序模块都链接成一个单独的可执行文件。Linux系统中,ELF动态链接文件被为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象,一般以.so为扩展名。

  由于共享对象是可以同时被很多进程共享的,所以我们不应该在编译共享对象的时候就把共享对象中的地址确定下来。如果确定下来了,由于每个进程的虚拟地址空间都不同,这样很难避免共享对象的地址空间和进程的其它地址空间冲突。

  如果不能在编译共享对象时确定共享对象的地址,能否在共享对象装载时确定呢?装载时重定位看起来好像是可以解决共享对象装载到任意虚拟地址空间的问题,都是在编译时目标地址不确定而需要在装载是将模块重定位。但是装载时重定位还是不适合用来解决共享对象所存在的问题。想象下,动态链接模块被装载到内存且被映射到虚拟地址空间后,指令部分是在多个进程之间共享的,由于装载时重定位的方法是需要修改指令的,所以没有办法做到同一份指令被多个进程所共享。当然,动态链接库中的可修改数据部分对于不同的进程来说有多个副本,所以它们可以采用装载时重定位的方法来解决。

  我们的目的很简单,就是希望程序模块中共享的指令在装载时不需要因为装载地址的改变而改变,所以实现的基本思想就是把指令中需要修改的部分分离出来,跟数据部分存放在一起,这样指令部分就可以保持不变了,而数据部分可以每个进程一个副本。这种技术就是PIC技术(Position-Independent Code)。ELF的具体做法是在数据段中建立一个指向其它模块变量地址的指针数组,称为全局偏移表(Global Offset Table,GOT),而代码中引用全局变量的代码都改成引用GOT。当代码中需要引用该全局变量时,就可以通过GOT相应项间接引用。

  动态链接下,程序模块之间包含了大量的函数引用(全局变量往往比较少,因为大量的全局变量引用会导致模块之间的耦合很大),所以在程序开始运行时,会消耗大量的时间来解决模块间函数引用的符号查找和重定位。实际上有很多的函数是不会调用的,如错误处理函数和用户很少使用的功能模块,一开始绑定就浪费资源和时间了。所以ELF采用了一种叫做延迟绑定的做法,基本思想就是当函数第一次被用到时才进行绑定,如果没用到就不绑定。ELF使用PLT(Procedure linkage table)的方法来实现延迟绑定。编译器将GOT分成GOT和GOT.PLT表,GOT用来保存全局变量的地址,GOT.PLT用来保存函数引用的地址。为了实现延迟绑定,我们就不能直接访问GOT表来获取目标函数的地址,必须又添加一层中间跳转表,这个中间跳转表叫做PLT表,由PLT表来真正完成绑定的工作。

ELF动态链接的更多相关文章

  1. ELF 动态链接 - so 的 .dynamic 段

    动态链接文件中最重要的段就是 .dynamic段 这个段里保存了动态链接器需要的最基本的信息 比如:1.  依赖于哪些共享对象, d_tag = DT_NEED,  d_ptr 表示共享对象文件名 2 ...

  2. ELF 动态链接 - so 的 重定位表

    动态链接下,无论时可执行文件还是共享对象,一旦对其他共享对象有依赖,也就是所有导入的符号时,那么代码或数据中就会有对于导入符号的引用.而在编译时期这些导入符号的确切地址时未知的.只有在运行期才能确定真 ...

  3. ELF 动态链接 so的动态符号表(.dynsym)

    静态链接中有一个专门的段叫符号表 -- ".symtab"(Symbol Table), 里面保存了所有关于该目标文件的符号的定义和引用. 动态链接中同样有一个段叫 动态符号表 - ...

  4. ELF 文件 动态链接 - 地址无关代码(GOT)

    Linux 系统中,ELF动态链接文件被称为 动态共享对象(DSO,Dynamic Shared Object),简称共享对象 文件拓展名为".so" 动态链接下 一个程序可以被分 ...

  5. 实例分析ELF文件动态链接

    参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台 ...

  6. ELF文件加载与动态链接(一)

    关于ELF文件的详细介绍,推荐阅读: ELF文件格式分析 —— 滕启明.ELF文件由ELF头部.程序头部表.节区头部表以及节区4部分组成. 通过objdump工具和readelf工具,可以观察ELF文 ...

  7. ELF文件加载与动态链接(二)

    GOT应该保存的是puts函数的绝对虚地址,这里为什么保存的却是puts@plt的第二条指令呢? 原来“解释器”将动态库载入内存后,并没有直接将函数地址更新到GOT表中,而是在函数第一次被调用时,才会 ...

  8. (九)ELF和动态链接

    前言: 我们都知道我们所写的程序是被编译为一条条的CPU指令去执行的,但是在linux系统下能够运行的程序在windows环境下却运行不起来,但是我们使用的CPU明明是一样的,这又是为什么呢? 一.程 ...

  9. [CSAPP-II] 链接[符号解析和重定位] 静态链接 动态链接 动态链接接口

    1 平台 转http://blog.csdn.net/misskissc/article/details/43063419 1.1 硬件 Table 1. 硬件(lscpu) Architecture ...

随机推荐

  1. libCURL开源库在VS2010环境下编译安装,配置详解

    libCURL开源库在VS2010环境下编译安装,配置详解 转自:http://my.oschina.net/u/1420791/blog/198247 http://blog.csdn.net/su ...

  2. LINUX 编译安装 PHP 环境

    今天终于有时间 总结一下 linux 的编译安装 php 环境同学给我发了他写的文档 ,基本就可以实现编译安装了我同学文章地址: http://penghui.link/articles/2016/0 ...

  3. 客户端连接注册Ejabberd新用户

    今天需要使用客户端注册新用户,结果发现注册失败,在管理后台添加新用户成功.编译安装ejabberd就没有管了,经过翻论坛的到解决方法 在ejabberd.yml中. access: trusted_n ...

  4. linux一句话轻松提权

    linux命令:‍ [b@fuckks~]$ printf "install uprobes /bin/sh" > exploit.conf; MODPROBE_OPTI** ...

  5. 微信第三方平台定时接收component_verify_ticket

    背景: 获取第三方平台令牌(component_access_token),增加了component_verify_ticket参数.component_verify_ticket由公众平台每隔10分 ...

  6. webform 分页、组合查询综合使用

    界面: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx ...

  7. oracle--导出、导入blob类型的字段

    blob是oracle中的一个数据类型,保存的是压缩后的二进制形式的大数据. 数据迁移如果涉及到blob字段,都不好处理,因为无法用常规方法进行操作,如:使用select查看该字段,也无法用inser ...

  8. 订单支付成功后存储过程 - MYSQL

    BEGIN SET @userId = (SELECT user_id FROM t_shoporder WHERE id = orderId); /*修改订单状态,改成已支付*/ ,update_t ...

  9. Python基本数据类型——str

    字符串常用操作 移除空白 分割 长度 索引 切片 class str(basestring): """ str(object='') -> string Retur ...

  10. Oracle_R12C_安装注意点_Win64_exectask

    安装问题1 原因 - 无法访问临时位置. 操作 - 请确保当前用户具有访问临时位置所需的权限. 附加信息: - 所有节点上的框架设置检查都失败 -原因: 问题的原因不可用 -操作:用户操作不可用 失败 ...