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. Linux之mailx的使用

    mailx是UNIX系统上用来处理邮件的工具,使用它可以发送,读取邮件.下面看看如何使用它来发送邮件. 发送格式 mailx -s subject user@xxx.com < message_ ...

  2. Android日历视图(CalendarView)讲解-android学习之旅(三十六)

    CalendarView简介 CalendarView用于显示和选择日期,如果希望监听事件的改变可以用setOnDateChangeListener()方法. CalendarView属性介绍 代码示 ...

  3. UNIX网络编程——网络层:IP

    一.IP数据报格式 IP数据报格式如下: 版本:IP协议版本号,长度为4位,IPv4此字段值为4,IPv6此字段值为6 首部长度:以32位的字为单位,该字段长度为4位,最小值为5,即不带任何选项的IP ...

  4. Android版本更新时对SQLite数据库升级或者降级遇到的问题

    SQLite是Android内置的一个很小的关系型数据库.SQLiteOpenHelper是一个用来辅助管理数据库创建和版本升级问题的抽象类.我们可以继承这个抽象类,实现它的一些方法来对数据库进行自定 ...

  5. Android Studio 使用 Gradle 打包 Jar

    Android Studio 打 Jar 包一直是一个麻烦的事,按照网上现有的教程,打包一个混淆的 jar 需要完成下列步骤: 1.将 plugin 修改为 library 后 build 出 aar ...

  6. Linux IPC实践(1) -- 概述

    进程的同步与互斥 进程同步: 多个进程需要相互配合共同完成一项任务. 进程互斥: 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥;系统中某些 ...

  7. ShapeDrawable做放大镜效果

    引用一下ShapeDrawable的类的说明: java.lang.Object    ? android.graphics.drawable.Drawable      ? android.grap ...

  8. 算法面试题-leetcode学习之旅(一)

    问题描述 Given an array of size n, find the majority element. The majority element is the element that a ...

  9. android 自定义下拉菜单

    本实例的自定义下拉菜单主要是继承PopupWindow类来实现的弹出窗体,各种布局效果可以根据自己定义设计.弹出的动画效果主要用到了translate.alpha.scale,具体实现步骤如下: 先上 ...

  10. Linux 用户打开进程数的调整

    Linux 用户打开进程数的调整 参考文章: 关于RHEL6中ulimit的nproc限制(http://www.cnblogs.com/kumulinux/archive/2012/12/16/28 ...