ELF动态链接
为什么要使用动态链接?
在现代的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动态链接的更多相关文章
- ELF 动态链接 - so 的 .dynamic 段
动态链接文件中最重要的段就是 .dynamic段 这个段里保存了动态链接器需要的最基本的信息 比如:1. 依赖于哪些共享对象, d_tag = DT_NEED, d_ptr 表示共享对象文件名 2 ...
- ELF 动态链接 - so 的 重定位表
动态链接下,无论时可执行文件还是共享对象,一旦对其他共享对象有依赖,也就是所有导入的符号时,那么代码或数据中就会有对于导入符号的引用.而在编译时期这些导入符号的确切地址时未知的.只有在运行期才能确定真 ...
- ELF 动态链接 so的动态符号表(.dynsym)
静态链接中有一个专门的段叫符号表 -- ".symtab"(Symbol Table), 里面保存了所有关于该目标文件的符号的定义和引用. 动态链接中同样有一个段叫 动态符号表 - ...
- ELF 文件 动态链接 - 地址无关代码(GOT)
Linux 系统中,ELF动态链接文件被称为 动态共享对象(DSO,Dynamic Shared Object),简称共享对象 文件拓展名为".so" 动态链接下 一个程序可以被分 ...
- 实例分析ELF文件动态链接
参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台 ...
- ELF文件加载与动态链接(一)
关于ELF文件的详细介绍,推荐阅读: ELF文件格式分析 —— 滕启明.ELF文件由ELF头部.程序头部表.节区头部表以及节区4部分组成. 通过objdump工具和readelf工具,可以观察ELF文 ...
- ELF文件加载与动态链接(二)
GOT应该保存的是puts函数的绝对虚地址,这里为什么保存的却是puts@plt的第二条指令呢? 原来“解释器”将动态库载入内存后,并没有直接将函数地址更新到GOT表中,而是在函数第一次被调用时,才会 ...
- (九)ELF和动态链接
前言: 我们都知道我们所写的程序是被编译为一条条的CPU指令去执行的,但是在linux系统下能够运行的程序在windows环境下却运行不起来,但是我们使用的CPU明明是一样的,这又是为什么呢? 一.程 ...
- [CSAPP-II] 链接[符号解析和重定位] 静态链接 动态链接 动态链接接口
1 平台 转http://blog.csdn.net/misskissc/article/details/43063419 1.1 硬件 Table 1. 硬件(lscpu) Architecture ...
随机推荐
- display:none与visible:hidden的区别
display:none和visible:hidden都能把网页上某个元素隐藏起来,但两者有区别: display:none ---不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就 ...
- angularjs 解决ng-repeat数组内重复对象报错的问题
ng-repeat 循环数组内元素时,如果数组内元素重复,angular会抛出异常: Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.3 ...
- Xamarin的不归路-ios模拟器调整窗口大小
ios模拟器调整窗口大小:
- oracle统计用户下面所有的表,并显示每个表的行数
declare t_count number(10); t_str VARCHAR2(500); cursor t_tables is select table_name from user ...
- 使用epel源安装软件
问题:centos提供的官方base源可能无法提供某些软件的安装,可以通过epel源 系统:centos6.5 x86_64 解决:安装epel源 #wget http://dl.fedoraproj ...
- WebP 原理和 Android 支持现状介绍(转)
本文为腾讯Bugly开发者社区 投稿,作者:soonlai,版权归原作者所有,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b70855 ...
- 编译链接 C++
预处理之后的源文件被称为一个编译单位,也即编译器的工作对象.为了使编译能够进行,程序员必须提供各种程序其他部分的声明来孤立分析一个编译单位.所有名字空间,类,函数都应该在他们所在的编译单位中有声明,所 ...
- Android四大组件--MediaPlayer详解(转)
一. MediaPlayer 状态机 介绍 Android MediaPlayer 状态即图例 : 1. Idle (闲置) 状态 和 End (结束) 状态 MediaPlayer 对象声明周期 : ...
- Mysql修改root密码
一.启动命令行,输入: taskkill /f /im mysqld.exe //关闭mysql 二.转入mysql的bin目录下 三.输入:mysqld --skip-grant-tables // ...
- Android Support Library
title: Android Support Library tags: Support Library,支持库 grammar_cjkRuby: true --- DATE: 2016-5-13. ...