ELF格式的重定位原理分析

前面有篇文章分析了ELF格式,也只是让我们对目标文件有了一个大概的了解,并没有说明一个十分重要的问题:重定位,今天重新看了下重定位的资料,终于弄懂了重定位的过程,下面来做一个分析。

我们将使用下面两个源代码中的文件a.c和b.c展开分析:

//a.c
extern int shared;
int main()
{
	int a=100;
	swap(&a,&shared);
}
//b.c
int shared=1;
void swap(int *a,int *b)
{
	*a^=*b^=*a^=*b;
}

使用命令:gcc -c a.c b.c生成两个可重定位目标文件a.o和b.o,下面就要使用链接器将a.o和b.o链接起来生成执行文件ab,我们分析的就是这个过程。

1.链接的过程

现在的链接器一般都是两步链接,也就是说整个链接过程分两步。

1)符号解析,主要使用ELF里面的符号表节来完成,不做描述。

2)重定位:一旦链接器完成符号解析这一步,它就把代码中的每个符号引用和定义联系起来。在此时,链接器就知道它的输入目标文件中的代码节和数据节的确切大小。现在就可以重定位了,在这个步骤中将合并输入模块,并为每个符号分配运行时地址。重定位由两步组成:

  • 重定位节和符号定义:在这一步中,链接器将所有相同类型的节合并为同一类型的新的聚合节。例如输入文件a.o的.text节和b.o中的.text节合并为可执行文件ab中的.text节。然后链接器将运行时存储器地址赋值给新的聚合节。当这一步完成时,程序中的每个指令和全局变量都有唯一的运行时存储器地址。
  • 重定位节中的符号引用:在这一步中,链接器修改代码节和数据节中对每个符号的引用,试的他们指向正确的运行时地址。为了执行这一步,链接器依赖于重定位条目。稍后我们来重点分析这一步骤的具体实现过程。

我们看到上面是a.o的各个段的分布情况,看到VMA列全都是0,VMA就是虚拟地址的意思,说明a.o中的节确实没有分配存储器运行时地址,根据上面描述,可执行文件ab中应该分配了虚拟地址,事实确实证明了这点:

我们发现VMA不再是0。可执行文件的代码段映射到08048094,数据段映射到08049108。

2.重定位的具体实现分析

先来看下重定位条目的内容:

RELOCATION RECORDS FOR [.text]:

OFFSET   TYPE              VALUE

0000001c R_386_32          shared

00000027 R_386_PC32        swap

OFFSET的意义:要修改的位置在.text节的偏移量

TYPE:重定位类型

VALUE:重定位符号的名称

R_386_32(绝对寻址修正):  objdump -d a.o

18:   c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)

1f:   00

movl指令要将shared的地址送到esp+4的位置,但是此时并不知道shared的地址,所以就先放00000000。在重定位条目中的第一项偏移是1c,刚好对应00000000。所以重定位的过程就是修改这个偏移处的内容。其实这个决定寻址修正很简单,只是书上各种符号公式看的让人迷惑。

修正过程:

假设shared符号的运行时地址是0x8049108,即ADDR(shared)=0x8049108。

要该修的位置的地址:就将00000000替换为ADDR(shared)即可。

R_386_PC32(相对寻址xiuzheng):ojbdump -d a.o

26:   e8 fc ff ff ff          call   27 <main+0x27>

相对寻址的意思就是相对当前IP位置跳转,call实现近转移,当前指令的ip+跳转位移=目标地址

我们先看可执行文件ab的反汇编代码:

也就是说0x8048bf+x=0x80480c8,算得x=9,正好是指令的操作数。

假设P是待修改的位置的虚拟地址,S是符号实际虚拟地址,那么P+4+x=S,所以x=S-P-4,即x=0x8048c8-4-0x8048bb=9.

ELF格式的重定位原理分析,布布扣,bubuko.com

时间: 2024-10-28 23:36:37

ELF格式的重定位原理分析的相关文章

linux下的ELF格式分析

ELF格式文档详解 一,ELF格式综述 ELF(Executable and Linkable Format)是Linux下的一种格式标准,Linux中的ELF格式文件一共有四种: ●可重定位文件(Relocatable File):这类文件包含了代码和数据,可被用来链接成可执行文件或者共享目录文件,扩展名为.o ●可执行文件(Executable File):这类文件包含了可以直接执行的程序,一般没有扩展名 ●共享目录文件(Shared Object File):这类文件包含了代码和数据,扩展

蓝牙Ibeacon室内定位和微信摇一摇周边原理分析

苹果推出Ibeacon室内定位技术是为了弥补GPS无法覆盖室内定位这种场景.苹果意味着创新,在其推动下,蓝牙Ibeacon得到了极大的应用.而腾讯则是利用蓝牙Ibeacon在场景体验方面进行了创新,实现了微信摇一摇周边的功能,这在O2O领域有巨大的潜力. 对苹果和腾讯来说,Ibeacon都是应用创新,而不是技术创新. 本文分析Ibeacon室内定位和微信摇一摇的原理. 一.无线测距原理 无线信号都有一个信号强度(RSSI),蓝牙BLE自然也有.根据蓝牙BLE自身的发射功率(假设能够获取这个功率值

ARM ELF函数重定位

ARM ELF的函数重定位与x86是一致的,但由于汇编指令不同,再鼓捣一遍. 示例代码: #include <stdio.h> #include <stdlib.h> int main () { puts ("Hello world"); sleep (1); FILE *fp = fopen ("1.c", "r"); fclose (fp); exit (0); } 通过 readelf -r 可以查看ELF中所有需要

3,gps定位原理及格式

1 gps定位原理 gps是美国开发的一套实时定位系统.在导航应用中,重点关注的是用户的gps接受机,根据接收机的数据从而获取当前的位置和时间信息.大概了解下定位原理: 由于我们是用于上位机的开发,接收器遵守的是NMEA0183协议,某种程度上我们通过协议直接得到当前所在的经纬度信息. 首先我们必须要了解的是地球的参考坐标系,以便于我们使用地图时把得到的坐标转换成导航所使用的坐标系.NMEA0183使用的参考坐标系是WGS-84坐标系. 其次,必须了解三颗卫星可以定位,另外一颗卫星是为了消除误差

elf格式分析

近期研究了一下elf文件格式,发现好多资料写的都比較繁琐,可能会严重打击学习者的热情,我把自己研究的结果和大家分享,希望我的描写叙述可以简洁一些. 一.基础知识 elf是一种文件格式,用于存储Linux程序. 它内部都有一些什么信息呢?大概包含编制好的计算机指令,数据,计算机在须要的时候把这个文件读取到内存中,cpu就能够从内存中一条一条的读取指令来运行了. 所以说想明确elf格式,我们应该了解一下计算机运行程序须要那些信息.所以这一节,我们补充一些计算机系统的基础知识. 进程和虚拟内存: Li

Java 重入锁 ReentrantLock 原理分析

1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生.ReentrantLock 的主要功能和 synchronized 关键字一致,均是用于多线程的同步.但除此之外,ReentrantLock 在功能上比 synchronized 更为丰富.比如 ReentrantLock 在加锁期间,可响应中断,可设置超时等. ReentrantLock 是我们

ELF Format 笔记(十)—— 重定位(relocation)

ilocker:关注 Android 安全(新手) QQ: 2597294287 重定位就是把符号引用与符号定义链接起来的过程,这也是 android linker 的主要工作之一. 当程序中调用一个函数时,相关的 call 指令必须在执行期将控制流转到正确的目标地址.所以,so 文件中必须包含一些重定位相关的信息,linker 据此完成重定位的工作. 这些重定位信息保存在一系列的重定位项中,重定位项的结构如下: 这些重定位项位于 .rel.plt section 中. r_offset:对于可

u-boot移植(三)---修改前工作:代码流程分析3---代码重定位

一.重定位 1.以前版本的重定位 2.新版本 我们的程序不只涉及一个变量和函数,我们若想访问程序里面的地址,则必须使用SDRAM处的新地址,即我们的程序里面的变量和函数必须修改地址.我们要修改地址,则必须知道程序的地址,就需要在链接的时候加上PIE选项: 加上PIE选项后,链接时候的地址就会生成,然后存储在段里面,如下段(u-boot.lds): 然后我们根据这些地址的信息来修改代码,程序就可以复制到SDRAM的任何地方去. 二.代码流程 start.S中执行到了 bl _main,跳转到_ma

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

动态链接下,无论时可执行文件还是共享对象,一旦对其他共享对象有依赖,也就是所有导入的符号时,那么代码或数据中就会有对于导入符号的引用.而在编译时期这些导入符号的确切地址时未知的.只有在运行期才能确定真正确切的地址 静态编译下,这些未知的地址会被编译器一一修正. 对于动态链接来说,共享文件有两种编译方式(gcc -shared 和 gcc -fPIC -shared) 如果不使用PIC模式编译,那么装载时肯定是要重定位的,而且时每个进程都有一个副本(相对比较占用内存) 如果使用PIC模式编译,将会