elf 格式 relocation 概念


author: hjjdebug

date: 2026年 01月 08日 星期四 15:12:21 CST

descrip: elf 格式 relocation 概念


文章目录

  • [1. 查看test 的重定位信息](#1. 查看test 的重定位信息)
  • [2. .rela.dyn 区与 .rela.plt 区的区别和联系](#2. .rela.dyn 区与 .rela.plt 区的区别和联系)
  • [3 概括动态绑定的过程](#3 概括动态绑定的过程)
  • [4. 介绍 .rela 结构](#4. 介绍 .rela 结构)
  • [5. r_info 的type 有多少种?](#5. r_info 的type 有多少种?)
  • [6. 补充: 节区表](#6. 补充: 节区表)

关于符号的概念,请参考链接:
计算机中符号是什么意思

elf 文件仍然采用链接中hello-world 产生的文件 test

1. 查看test 的重定位信息

$ readelf -r test

重定位节 '.rela.dyn' at offset 0x380 contains 2 entries:

偏移量 信息 类型 符号值 符号名称 + 加数

000000600ff0 000200000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0

000000600ff8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 gmon_start + 0

重定位节 '.rela.plt' at offset 0x3b0 contains 1 entry:

偏移量 信息 类型 符号值 符号名称 + 加数

000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0

2. .rela.dyn 区与 .rela.plt 区的区别和联系

.rela.dyn 和 .rela.plt 是ELF文件格式中用于动态链接的重定位节,

相同点:

从结构上看, .rela.dyn 和 .rela.plt 的重定位条目结构相同(均基于ELF64_Rela或ELF32_Rela),

RELA结构(包含Addend字段),但用途和处理对象有明确区别。

不同点:前者关联动态符号表(.dynsym节)中的数据符号,后者关联动态符号表(.dynsym节)中的函数符号。

.rela.dyn 处理数据符号(如全局变量、静态变量等)的重定位,其重定位目标通常位于.got节中;

.rela.plt 处理函数符号的重定位,目标位于.got.plt节中。

这种分工源于动态链接机制不同:数据引用和函数调用需要不同的绑定策略。

.rela.dyn 通常在程序加载时完成重定位,用于修正数据符号的地址;

.rela.plt 支持延迟绑定(Lazy Binding),即函数重定位在首次调用时才完成,通过.plt节(过程链接表)和.got.plt节协作实现,以提升程序启动效率。

具体延迟绑定细节可以参考以下链接
elf 文件动态加载过程

3 概括动态绑定的过程

这里概括一下, 外部printf函数由于其只调用了字符串太简单被简化为puts 函数调用. 这部分会形成一小段调用代码位于plt.sec 节中

为 jmp (*addr), 从指定的地址中取出目标地址, 到那个地址中去执行

这部分 plt.sec 是代码区, 是不能改的. 可改的是addr 处存储的地址.

那个地址是函数实际的入口地址, 但第一次调用时还不是,第一次调用存储的是地址解析函数调用地址.

其中 addr 所处的那个节叫 .got.plt, 就是说它将来存储实际函数入口地址,第一次存储地址解析函数地址. 是可更改的.

地址解析函数地址所处的节叫plt 节, 也是代码节,不可更改. 它的代码是这样的.

push 0

jmpq resolve

第二个函数调用则是

push 1

jmpq resolve

resolve地址解析函数很厉害, 它根据槽位号能找到外部绑定的函数名,并能确定外部函数地址,并将结果存储到.got.plt对应位置处.

解析一次,以后就不会跳到这里了,而是直接跳转到真实地址去了.

4. 介绍 .rela 结构

首先, 重定位是对符号的重定位, 所以被重定位的符号名称是一项内容.

被重定位的符号值, 肯定都是0. 不知道为什么要定义它

类型. 是外部变量还是外部函数等.

偏移量. 是说明在内存的什么地址来修改, 把原来的0改为解析到的地址.

信息. 就是其它的属性信息.

有了这些基础,我们再看elf64.h 中的结构定义

结构很简单,三个变量. 都是8bytes 数据

typedef struct

{

Elf64_Addr r_offset; /* Address /
Elf64_Xword r_info; /
Relocation type and symbol index /
Elf64_Sxword r_addend; /
Addend */

} Elf64_Rela;

typedef uint64_t Elf64_Addr;

typedef uint64_t Elf64_Xword;

typedef int64_t Elf64_Sxword;

r_offset指示需要修改的地址

r_info的高32位指向符号表索引,低32位指定重定位类型

符号值 + r_addend得到最终地址

r_addend 一般是0, 不是0的情况以后碰到再给实例吧.

5. r_info 的type 有多少种?

复制代码
switch(ELF64_R_TYPE(r_info)) {
    case 1: return "R_X86_64_32";
    case 2: return "R_X86_64_PC32";
    case 5: return "R_X86_64_COPY";
    case 6: return "R_X86_64_GLOB_DAT";
    case 7:  return "R_X86_64_JUMP_SLOT";
    default: return "OTHERS";

6. 补充: 节区表

想看看前边提到的重定位地址 0x600ff0, 0x600ff8, 0x601018属于哪个节区,

可以打出节表, 如下. 即知:

0x600ff0,0x600ff8 属于 .got 区

0x601018 属于 属于 .got.plt 区

cpp 复制代码
$ readelf -S test
There are 34 section headers, starting at offset 0x2120:

节头:
  [号] 名称              类型             地址              偏移量
       大小              全体大小          旗标   链接   信息   对齐
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       0000000000000060  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400318  00000318
       000000000000003d  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400356  00000356
       0000000000000008  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400360  00000360
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400380  00000380
       0000000000000030  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             00000000004003b0  000003b0
       0000000000000018  0000000000000018  AI       5    22     8
  [11] .init             PROGBITS         00000000004003c8  000003c8
       0000000000000017  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000004003e0  000003e0
       0000000000000020  0000000000000010  AX       0     0     16
  [13] .text             PROGBITS         0000000000400400  00000400
       0000000000000172  0000000000000000  AX       0     0     16
  [14] .fini             PROGBITS         0000000000400574  00000574
       0000000000000009  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         0000000000400580  00000580
       000000000000000a  0000000000000000   A       0     0     4
  [16] .eh_frame_hdr     PROGBITS         000000000040058c  0000058c
       000000000000003c  0000000000000000   A       0     0     4
  [17] .eh_frame         PROGBITS         00000000004005c8  000005c8
       0000000000000100  0000000000000000   A       0     0     8
  [18] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000008  WA       0     0     8
  [19] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .dynamic          DYNAMIC          0000000000600e20  00000e20
       00000000000001d0  0000000000000010  WA       6     0     8
  [21] .got              PROGBITS         0000000000600ff0  00000ff0
       0000000000000010  0000000000000008  WA       0     0     8
  [22] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000020  0000000000000008  WA       0     0     8
  [23] .data             PROGBITS         0000000000601020  00001020
       0000000000000010  0000000000000000  WA       0     0     8
  [24] .bss              NOBITS           0000000000601030  00001030
       0000000000000008  0000000000000000  WA       0     0     1
  [25] .comment          PROGBITS         0000000000000000  00001030
       0000000000000029  0000000000000001  MS       0     0     1
  [26] .debug_aranges    PROGBITS         0000000000000000  00001059
       0000000000000030  0000000000000000           0     0     1
  [27] .debug_info       PROGBITS         0000000000000000  00001089
       000000000000031d  0000000000000000           0     0     1
  [28] .debug_abbrev     PROGBITS         0000000000000000  000013a6
       00000000000000e0  0000000000000000           0     0     1
  [29] .debug_line       PROGBITS         0000000000000000  00001486
       00000000000000d1  0000000000000000           0     0     1
  [30] .debug_str        PROGBITS         0000000000000000  00001557
       0000000000000284  0000000000000001  MS       0     0     1
  [31] .symtab           SYMTAB           0000000000000000  000017e0
       0000000000000630  0000000000000018          32    48     8
  [32] .strtab           STRTAB           0000000000000000  00001e10
       00000000000001c8  0000000000000000           0     0     1
  [33] .shstrtab         STRTAB           0000000000000000  00001fd8
       0000000000000143  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

参考代码: https://gitee.com/hejinjing/elf-parser.git

相关推荐
程序猿编码1 个月前
恶意软件分析工具:ELF二进制文件的感染与分析原理(C/C++代码实现)
c语言·c++·网络安全·信息安全·elf·shellcode
再睡一夏就好1 个月前
深入理解Linux程序加载:从ELF文件到进程地址空间的完整旅程
linux·运维·服务器·c++·学习·elf
计算衎2 个月前
.c .o .a .elf .a2l hex map 这些后缀文件的互相之间的联系和作用
开发语言·elf·gcc·c/c++·a2l
egoist20233 个月前
[linux仓库]解剖ELF:从文件头到进程地址空间的完美映射
linux·elf·虚拟地址空间·静态链接
玥轩_5217 个月前
BUUCTF [UTCTF2020]File Carving 1
安全·网络安全·elf·ctf·misc·buuctf·png隐写
Android小贾2 年前
鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main
汇编·移动开发·harmonyos·elf·openharmony·鸿蒙开发·内核机制
如影随从2 年前
02 - ArcGIS For JavaScript-矢量数据的符号化处理(Symbol)
开发语言·javascript·arcgis·symbol·符号化
张一西2 年前
ARM学习(25)链接装载高阶认识
elf·编译链接·链接装载·目标文件·静态链接·abi·链接脚本
_Jyann_2 年前
ES6 Symbol 数据结构
symbol