ELF--动态链接
对前面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--动态链接的更多相关文章
- ELF动态链接
为什么要使用动态链接? 在现代的linux系统中,假设一个普通的程序会使用到c语言静态库至少1MB以上,那么,如果我们的机器运行100个这样的程序,就用浪费近100MB的内存:如果磁盘有2000个这样 ...
- 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 ...
随机推荐
- TCP握手
1.TCP的三次握手四次挥手 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认. 第二 ...
- js match regex
需要返回成数组元素的要放在括号里头 var arr = /input-([0-9]*)-([0-9]*)/.exec(id); var all = arr[0]; var row = arr[1]; ...
- HEAD
Branches are just pointers to commits Every branch is simply a named pointer to a commit. A special ...
- [Everyday Mathematic]20150217
设 $f:\bbR\to\bbR$ 二阶可微, 适合 $f(0)=1$, $f'(0)=0$, 并且 $$\bex f''(x)-5f'(x)+6f(x)\geq 0. \eex$$ 试证: $$\b ...
- 通过DDOS攻击流程图来浅谈如何预防Ddos攻击与防御
DDOS攻击流程图 站长之家配图(来源:ppkj.net) 一 背景 在前几天,我们运营的某网站遭受了一次ddos攻击,我们的网站是一个公益性质的网站,为各个厂商和白帽子之间搭建一个平台以传递安全问题 ...
- 性能测试之系统监控工具nmon
一.概述 本篇文章主要讲解nmon,以下为目录 1.nmon介绍 2.nmon下载.安装及使用 3.nmon analysis 分析及使用,各个项的含义 二.详细信息: 1.nmon介绍: nmon( ...
- Linux上修改weblogic的内存大小
我们经常在使用WebLoigc部署应用程序后,发现程序运行速度并不是很快,遇到这种情况我们可以尝试调整启动时分配的内存,设置方法有两种: 一.在../domain/setDomainEnv.sh文件中 ...
- Java 分割文件 注意事项
public static void main(String args[]) throws Exception { if (args.length < 1) { System.exit(0); ...
- MySql 5.6 查询日志
记录所有查询的方法 打开My.ini 在 [mysqld]下面写 general_log= ON; log_output= TABLE; 然后保存重启mysql 最后在mysql库下 general_ ...
- focus与定位
<html> <head> <script type="text/javascript" src="/jquery/jquery.js&qu ...