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

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

静态编译下,这些未知的地址会被编译器一一修正。

对于动态链接来说,共享文件有两种编译方式(gcc -shared 和 gcc -fPIC -shared)

如果不使用PIC模式编译,那么装载时肯定是要重定位的,而且时每个进程都有一个副本(相对比较占用内存)

如果使用PIC模式编译,将会在编译期生成地址无关代码(PIC Position-Independent Code),则代码段可以实现多程序共享,而仅数据段部分会在每个程序中有一个副本(节省内存)

对于这两种模式来说都是要重定位的,当相对PIC模式编译的模块仅需要对数据段进行重定位(因为代码段中的绝对地址引用部分被分离到了GOT中,而GOT是数据段的一部分;数据段中也可能包含绝对地址的引用,正好重定位数据段)

静态链接中,目标文件里面包含有用于重定位的表:代码段重定位表“.rel.text”;数据段重定位表“.rel.data”。

动态链接中,目标文件的重定位表:“.rel.dyn”对数据引用的修正,修正的位置位于“.got”和数据段;“.rel.plt”对函数引用的修正,修正位置位于“.got.plt”。

可以通过readelf 查看一个动态链接文件的重定位表

1 readelf -r XXX.so

这里可以看到几种重定位入口类型:

R_386_RELATIVE  R_386_GLOB_DATR_386_JUMP_SLOT

R_386_GLOB_DAT(.rel.dyn中针对.got)R_386_JUMP_SLOT(.rel.plt中针对.got.plt)表示被修正的位置只需要直接将符号的地址填入。

而在重定位表中的列Offset 表明了当前符号在“.got" 或“.got.plt”中的偏移,可以根据该值在两个GOT表中寻找对应的位置,填入(连接器在全局符号表中查找)真实的外部符号地址。

R_386_RELATIVE 是基址重置。有些共享对象的数据段是无法做到地址无关的,比如:

static int a;
static int *p = &a;

由于共享对象编译时,基址是从0开始的,所以a的地址(在未重定位时)是相对与起始地址0的偏移(假设为B),则此时p的值为B;

而当共享对象装载到指定进程中的地址C时,则变量a的地址将编程B+C,即p的值需要加上装载的地址B。

R_386_RELATIVE 类型就是专门用来重定位指针变量p这种类型的。

原文地址:https://www.cnblogs.com/gradyblog/p/8964073.html

时间: 2024-11-01 12:26:05

ELF 动态链接 - so 的 重定位表的相关文章

了解动态链接(六)—— 重定位表

柳条青青,南风熏熏,幻化奇峰瑶岛,一天的黄云白云,那边麦浪中间,有农妇笑语殷殷.问后园豌豆肥否,问杨梅可有鸟来偷:好几天不下雨了,玫瑰花还未曾红透:梅夫人今天进城去,且看她有新闻无有.—— 徐志摩·夏日田间即景 无论是可执行文件还是 so,只要它依赖于其他 so(.dynsym 动态符号表中有导入符号存在),那么在编译链接阶段,这些符号的地址未知,所以只能在动态链接阶段对其进行地址重定位. 注意:以 PIC 编译的 so,虽然称“地址无关代码”,但也需要重定位.因为对于 PIC 的 so 来说,

链接脚本与重定位

目录 链接脚本与重定位 总结 链接脚本格式 COMM段BSS段 elf和bin文件 获得链接脚本的值 重定位 1-直接指定数据段位置(代码黑洞) 2-分散加载(数据段) 3-全局重定位(一体式) BL跳转指令 bss段处理 汇编处理 C处理 位置无关码 title: 链接脚本与重定位 tags: ARM date: 2018-10-12 19:25:53 --- 链接脚本与重定位 学习视频 韦东山 总结 尽量使用一体式的链接脚本,方便简单,灵活 学会使用链接脚本的值 bss段和comm段是需要我

也谈PE重定位表

最近研究脱壳,遇到了dll,所以不可避免的需要修复重定位表.以前研究过也脱过不少壳,但都是exe从来没有手工修过重定位表,于是搜索之,恩有这么一篇:<PE重定位表学习手记>,有刚巧手上有看雪段钢等编著的<加密与解密>,一并阅读. <PE重定位表学习手记>中说到: 每个块的首部是如下定义: typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; } IMAGE_BAS

解析PE资源表与重定位表

#include<Windows.h> #include<iostream> #include<stdio.h> #include<stdlib.h> #include<commdlg.h> using namespace std; DWORD dwFileSize; BYTE* g_pFileImageBase = 0; PIMAGE_NT_HEADERS g_pNt = 0; DWORD RVAtoFOA(DWORD dwRVA); //显示

PE知识复习之PE的重定位表

PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思.  如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234.  如果Imagebase 变了成了0x300000, 那么修正之后就是 ImageBase + RVA = 0X300000+1234 = 0x301234. 首先我们知道.一个EXE文件.会调用很多DLL(PE) 有多个PE文件组成. exe文件启动的基址 (ImageBase) 是0x40000. 假设我

重定位表 IMAGE_BASE_RELOCATION

typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; // WORD TypeOffset[1]; } IMAGE_BASE_RELOCATION; typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION; VirtualAddress:页起始地址RVA. SizeOfBlock:表示该分组保存了几项重定位项. Ty

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

1 平台 1.1 硬件 Table 1. 硬件(lscpu) Architecture: i686(Intel 80386) Byte Order: Little Endian 1.2 操作系统 Table 2. 操作系统类型 操作系统(cat /proc/version) 位数(uname -a) Linux version 3.2.0-4-686-pae i686(32bit) 1.3 编译器 Table 3. 编译器信息 编译器(gcc -v) gcc (Debian 4.7.2-5) 4

装载与动态链接

装载与动态链接 1可执行文件的装载与进程 可执行文件只有装载到内存后才能被CPU执行.早期的程序装载十分简陋,装载的基本过程就是把程序从外部存储器中读取到内存中的某个位置. 历史有过的装载方式包括覆盖装载.页映射. 1.1 进程虚拟地址空间 程序是一个静态的概念,它就是一些预先编译好的指令和数据集合的一个文件:进程则是一个动态的概念,它是程序运行的一个过程. 每个程序被运行起来以后,都有自己的虚拟地址空间,这个虚拟地址空间的大小由计算机的硬件平台决定,具体地说是由CPU的位数决定的. 1.2 装

实例分析ELF文件动态链接

参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台: [[email protected] dynamic_link]# uname -a Linux tanghuimin 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 实例讲解