对前面add.c稍作修改,

#include <stdio.h>
int add_count = 0;

extern int sum_count;
extern void print_log(const char *ident, int line);
int add2(int num1, int num2)
{
  int result= 0;
  result = num1 + num2;

add_count ++;
  return result;
}
int sum(int num1, int num2, int num3)
{

sum_count++;

  int sum = add2(num1, num2);
  return add2(sum, num3);
}

编译成so gcc -shared -fPIC add.c -o libadd.so。查看ELF program header.

和可执行文件类似,只是LOAD的virtAddr起始地址是0x0.说明so在load到内存中时地址是不确定的。

当系统在装载某个包含so的进程时,也需要装载so。装载器会更具当前地址空间的空闲情况,动态分配一块足够大小的虚拟地址空间给so。

当进程在调用so中的函数和数据时,需要知道这些函数的绝对地址.我们知道函数sum的相对地址0x568,那如何知道他的绝对地址呢。

假设so被装载的目标地址为0x10000000,那么sum的绝对地址为0x10000568.

为使so能够被多个进程link,并节省内存。so需要分离出地址无关代码。主要是希望将so指令部分不要因为装载地址的改变而改变。所以基本想法是将指令中需要被修改的部分分理出来,更数据放在一起。而将指令中不变的部分保持不变,各个进程共享。各个进程各自拥有so数据的副本。

对于add.c文件中内部的函数调用和数据访问,是地址无关的。

对于add.c中文件间函数调用和数据访问,是通过GOT来实现的。当程序要访问变量sum_count或调用print_log是,首先找到GOT,根据GOT中对应项找到地址。在so装载时,会查找sum_count和print_log的地址,并填充到GOT中,每一项对应4字节地址。具体sum_count,printf_log对应于GOT的哪一项,可以通过重定位表来查看。

GOT是放在数据段,所以它是可以在so装载时被修改的,并且每个进程都拥有副本。

查看libadd.so的section header可以看到.got的起始地址0x1fe8:

查看libadd.so的重定位表:readelf -r libadd.so. (rel.dyn 和.rel.plt分别相当于.rel.data和.rel.plt. .rel.dyn是对数据引用的修正,修正的位置位于.got。.rel.plt是对函数引用的修正,修正的位置位于.got.plt)

引用的外部变量sum_count正好在.got中。

而print_log则在.got.plt中。这是由于编译时采用了延迟绑定。

为什么要使用延迟绑定呢?在动态链接下,模块间有大量函数调用,在程序开始执行时,动态链接器会耗费大量时间去解决函数符号的查找和重定位。但是实际上程序运行时可能只有少数函数才回用到,所以会delay程序启动时间。因此ELF采用延迟绑定,只有函数第一次用到才会绑定。

采用延迟绑定后,当调用外部函数时,并不直接通过.got跳转,而是通过.got.plt跳转。每个外部函数都在.got.plt中有一项。比如print_log在.got.plt是printf_log@plt.

.got.plt的前三项是.dynamic地址,本模块的ID,_dl_runtime_resolve的地址。_dl_runtime_resolve是动态连接器函数,用来完成符号解析和重定位,将函数的真正地址放到.got表对用的项中,如print_log@GOT.

反汇编objdump -d libadd.so

在调用print_log时,跳转到print_log@plt

在.got.plt中前三项保留,jmp到表中第4项0x0c,push 0x0,0x0代表print_log在rel.plt中的下标,然后跳转到450位置。

在450位置,push .got.plt第二项模块ID,然后跳转到第三项_dl_runtime_resolve完成符号解析和重定位。

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

  1. ELF动态链接

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. (九)ELF和动态链接

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

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

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

随机推荐

  1. iOS 9的新内容

    https://www.hackingwithswift.com/ios9 Search extensibility Update: I wrote a tutorial on Core Spotli ...

  2. 【JavaScript学习笔记】鼠标样式

    style="cursor:hand"   手形 style="cursor:crosshair"   十字形       style="cursor ...

  3. 【英语】Bingo口语笔记(40) - [aʊ]的发音规则

    [aʊ]的发音规则 先发音标的音再去拼出单词的读音down

  4. 【英语】Bingo口语笔记(45) - Pass系列

  5. SpringMVC注解@initbinder解决类型转换问题

    在使用SpringMVC的时候,经常会遇到表单中的日期字符串和JavaBean的Date类型的转换,而SpringMVC默认不支持这个格式的转换,所以需要手动配置,自定义数据的绑定才能解决这个问题.在 ...

  6. java-No exception of type ConfigurationException can be thrown; an exception type must be a subclass of Throwable

    功能:读配置文件 java菜鸟:导入工程在报名处就开始报错,第一次遇到 import org.apache.commons.lang3.StringUtils; import org.apache.c ...

  7. Informatica9.6.1在Linux Red Hat 5.8上安装遇到的有关问题整理_3

    3.Repository Service启动后的页面编码问题 1)错误信息: 2)原因分析及解决步骤 原因分析: informatica产品安装背后AdminConsole的Code page默认为U ...

  8. C# "error CS1729: 'XXClass' does not contain a constructor that takes 0 arguments"的解决方案

    出现这种错误的原因时,没有在子类的构造函数中指出仅有带参构造函数的父类的构造参数. 具体来讲就是: 当子类要重用父类的构造函数时, C# 语法通常会在子类构造函数后面调用 : base( para_t ...

  9. Nginx工作原理和优化、漏洞

    1.  Nginx的模块与工作原理 第三方模块:HTTP Upstream Request Hash模块.Notice模块和HTTP Access Key模块. 图1-1展示了Nginx模块常规的HT ...

  10. 9、NFC技术:NDEF文本格式解析

    NDEF文本格式规范     不管什么格式的数据本质上都是由一些字节组成的.对于NDEF文本格式来说.这些数据的第1个字节描述了数据的状态,然后若干个字节描述文本的语言编码,最后剩余字节表示文本数据. ...