Linux 系统中,ELF动态链接文件被称为 动态共享对象(DSODynamic Shared Object),简称共享对象

文件拓展名为“.so”

动态链接下 一个程序可以被分成若干个文件:程序的主要部分 - 可执行文件 和 程序所依赖的共享对象(一个或多个.so文件),它们都可称作为程序的模块。

动态链接文件(共享对象)的装载地址为0x00000000;这并非工作时的实际地址,实际地址由装载器根据当前进程地址空间的空闲情况来动态分配一块足够大的虚拟地址空间给共享对象。

装载时重定位

基本思路:在链接时对所有的绝对地址的引用不作重定位,而把这一步放在装载时完成。一旦模块装载完成,既目标地址确定,那么系统将对程序中的所有绝对地址的引用进行重定位。

静态链接时的重定位称为 链接时重定位(Link Time Relocation)

动态链接时的重定位称为 装载时重定位(Load Time Relocation) gcc -shared

然而光有装载时重定位也不能解决所有问题,因为对于动态链接文件来讲,它时可以分为可修改数据部分和不可修改数据部分,如果只有装载重定位,那每个程序必须都有一个共享对象的副本,这样会很浪费内存

这样就引入来下一个话题

地址无关代码 (gcc -shared -fPIC)

基本思想: 把指令中需要被修改的部分分离出来,跟数据部分放在一起,这样指令部分就保持不变了,而数据部分为每个进程都有一个副本,

这就是地址无关代码(PIC, Position-independent Code)技术

共享对象模块内的地址引用分为四种情况:

1. 模块内部调用或跳转:

    它们之间位置固定,使用相对地址调用。

2. 模块内部数据访问

    同样使用相对寻址(使用当前(指令地址)PC + 偏移量)

3. 模块与模块之间的数据访问(重点)

    模块之间的数据访问,其目标地址需要等到装载后才能确定。

    这里的基本思想时将这部分与地址相关的指令的当前地址放入到数据段里面。

    ELF 的做法是在数据段中建立了一个 指向这些变量的指针数组 ,也被称为 全局偏移表(GOT, Global Offset Table),当代码需要引用该全局变量时,通过GOT间接引用,

    即GOT中记录着该外部函数真正的地址,装载器在做动态链接时,会查找每个外部符号的地址,然后填充到GOT的对应的项中。

    GOT 如何做到与指令无关的呢?(在.so 文件中对应 .got 段)

    1. 模块在编译期可以确定模块内部变量相对与当前指令的偏移,同样在编译期也可以确定GOT相对于当前指令的偏移。确定GOT的位置和确定内部变量的位置方法上时一样的,通过

     得到PC值然后加上一个偏移量即可得到GOT的位置。当然GOT中的每个地址对应于哪个符号(变量,函数都是符号)由编译期决定。

4. 模块间跳用和跳转

    此时与3.中方法类似,只是对应的GOT的位置保存的时目标函数的地址,通过GOT实现间接跳转

地址无关小结:

                    各种引用方式
  指令跳转和调用  数据访问
模块内部  相对跳转调用  相对访问
模块外部 GOT间接跳转访问 GOT间接跳转访问

ELF 文件 动态链接 - 地址无关代码(GOT)的更多相关文章

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

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

  2. Cortex-M3 动态加载一(地址无关代码实现)

    这篇文章是自己疑惑究竟地址无关性是如何实现,然后查看汇编和CPU指令手册,最后分析解除自己疑惑的,高手不要鄙视,哈哈. 编译C代码时候需要制定--acps/ropi选项,如下例子: void Syst ...

  3. 实例分析ELF文件静态链接

    参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第4章 静态链接 开发平台: [thm@tanghuimin static_link]$ uname ...

  4. (九)ELF和动态链接

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

  5. ELF 文件 动态连接 - 延迟绑定(PLT)

    PLT 全称:Procedure Linkage Table ,直译:过程连接表 由于在动态连接中,程序的模块之间包含了大量的函数引用,所以在程序开始执行前,动态链接会耗费较多的时间用于模块之间函数引 ...

  6. Delphi通过Map文件查找内存地址出错代码所在行

    一 什么是MAP文件 什么是 MAP 文件?简单地讲, MAP 文件是程序的全局符号.源文件和代码行号信息的唯一的文本表示方法,它可以在任何地方.任何时候使用,不需要有额外的程序进行支持.而且,这是唯 ...

  7. 问题-[Delphi]通过Map文件查找内存地址出错代码所在行

     一 什么是MAP文件       什么是 MAP 文件?简单地讲, MAP 文件是程序的全局符号.源文件和代码行号信息的唯一的文本表示方法,它可以在任何地方.任何时候使用,不需要有额外的程序进行支持 ...

  8. ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)

    加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: ...

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

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

随机推荐

  1. 从Eclipse插件中读取资源

    可以通过Eclipse里的OSGi的Bundle类,获取插件目录下的某个文件的输入流: 1. Bundle bundle = Platform.getBundle(Activator.PLUGIN_I ...

  2. Dynamics CRM 在报表中获取当前登陆用户的guid

    <span style="font-size:18px;">CRM提供函数,只需在报表中调用即可.</span> <pre class="s ...

  3. 【一天一道LeetCode】#102. Binary Tree Level Order Traversal

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 来源: htt ...

  4. linux下JAVA开发的环境配置

    1.去http: //java.sun.com/j2se/1.4.2/download.html 下载一个Linux Platform的JDK,建议下载RPM自解压格式的(RPM in self-ex ...

  5. Cocos2D:塔防游戏制作之旅(十七)

    getHpDamage方法当敌人到达基地时被调用.你需要添加该方法到Enemy.m的update:方法中去,以便检查当敌人到达基地是会发生什么.幸运的是,你已经在之前的代码中实现这些了,你可以接着往下 ...

  6. android异步任务asyntask详解

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更 ...

  7. 显示 Ubuntu 11.10 的 终端窗口

    显示 Ubuntu 11.10 的 终端窗口 一.点击左上角的图标 -> 在search框里搜索termial . 二.快捷键:Ctrl+Alt+t.

  8. Google的两种广告推广方式

    1搜索关键字广告推送:AdWords: 覆盖广泛:在全球最大的搜索和网络平台上进行推广. 定位精准:锁定目标客户群体,让潜在客户轻松找上门. 成本可控:仅当用户点击广告时,您才支付费用. 2.网站内容 ...

  9. sql一些常用的经典语句,最后是select as的用法

    总结一些工作中用到或碰到的SQL语句,希望能与大家分享,同时也希望大家能提供更多的精妙SQL语句..... 1.delete table1 from (select * from table2) as ...

  10. Python学习笔记 - dict和set

    dict #!/usr/bin/env python3 # -*- coding: utf-8 -*- #dict >>> d = {'Michael': 95, 'Bob': 75 ...