Linux可执行文件ELF文件结构

news2025/6/7 17:33:05

目标文件格式

编译器编译源代码后生成的文件叫做目标文件,而目标文件经过编译器链接之后得到的就是可执行文件。那么目标文件到底是什么?它和可执行文件又有什么区别?链接到底又做了什么呢?接下来,我们将探索一下目标文件的本质。

目前,PC平台流行的 可执行文件格式(Executable) 主要包含如下两种,它们都是 COFF(Common File Format) 格式的变种。

  • Windows下的 PE(Portable Executable)
  • Linux下的 ELF(Executable Linkable Format)
    目标文件就是源代码经过编译后但未进行链接的那些中间文件(Windows的.obj和Linux的.o),它与可执行文件的格式非常相似,所以一般跟可执行文件格式一起采用同一种格式存储。在Windows下采用PE-COFF文件格式;Linux下采用ELF文件格式。

事实上,除了可执行文件外,动态链接库(Dynamic Linking Library)、静态链接库(Static Linking Library) 均采用可执行文件格式存储。它们在Window下均按照PE-COFF格式存储;Linux下均按照ELF格式存储。只是文件名后缀不同而已。

  • 动态链接库:Windows的.dll、Linux的.so
  • 静态链接库:Windows的.lib、Linux的.a

本文将以Linux ELF文件为例进行介绍。

ELF文件结构

在这里插入图片描述

如图所示,为ELF文件的基本结构,其主要由四部分组成:

  • ELF Header
  • ELF Program Header Table (或称Program Headers、程序头),可选,当目标为.o文件时无此字段
  • ELF Section Header Table (或称Section Headers、节头表)
  • ELF Sections

1.ELF Header

我们可以使用readelf -h来查看ELF Header。readelf 和 objdump 的源码位于 binutils 源码包中,下载地址点这里,对于 elf 文件格式的读取以及解析参考 binutils/readelf.c,include/elf/external.h的实现即可。

64位ELF Header

root@DESKTOP-90KJ7MS:/usr/src/bluetooth/bluez_ins/lib# readelf -h libexpat.so
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x37e0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          709336 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         35
  Section header string table index: 34
typedef struct {
  unsigned char	e_ident[16];		/* ELF "magic number" */
  unsigned char	e_type[2];		/* Identifies object file type */
  unsigned char	e_machine[2];		/* Specifies required architecture */
  unsigned char	e_version[4];		/* Identifies object file version */
  unsigned char	e_entry[8];		/* Entry point virtual address */
  unsigned char	e_phoff[8];		/* Program header table file offset */
  unsigned char	e_shoff[8];		/* Section header table file offset */
  unsigned char	e_flags[4];		/* Processor-specific flags */
  unsigned char	e_ehsize[2];		/* ELF header size in bytes */
  unsigned char	e_phentsize[2];		/* Program header table entry size */
  unsigned char	e_phnum[2];		/* Program header table entry count */
  unsigned char	e_shentsize[2];		/* Section header table entry size */
  unsigned char	e_shnum[2];		/* Section header table entry count */
  unsigned char	e_shstrndx[2];		/* Section header string table index */
} Elf64_External_Ehdr;

32位ELF Header

root@DESKTOP-90KJ7MS:/usr/src/helloworld# readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x1030c
  Start of program headers:          52 (bytes into file)
  Start of section headers:          6872 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 28
root@DESKTOP-90KJ7MS:/usr/src/helloworld# readelf -h hello.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          552 (bytes into file)
  Flags:                             0x5000000, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11
typedef struct {
  unsigned char	e_ident[16];		/* ELF "magic number" */
  unsigned char	e_type[2];		/* Identifies object file type */
  unsigned char	e_machine[2];		/* Specifies required architecture */
  unsigned char	e_version[4];		/* Identifies object file version */
  unsigned char	e_entry[4];		/* Entry point virtual address */
  unsigned char	e_phoff[4];		/* Program header table file offset */
  unsigned char	e_shoff[4];		/* Section header table file offset */
  unsigned char	e_flags[4];		/* Processor-specific flags */
  unsigned char	e_ehsize[2];		/* ELF header size in bytes */
  unsigned char	e_phentsize[2];		/* Program header table entry size */
  unsigned char	e_phnum[2];		/* Program header table entry count */
  unsigned char	e_shentsize[2];		/* Section header table entry size */
  unsigned char	e_shnum[2];		/* Section header table entry count */
  unsigned char	e_shstrndx[2];		/* Section header string table index */
} Elf32_External_Ehdr;

ELF文件结构示意图中定义的Elf_Ehdr的各个成员的含义与readelf具有对应关系。如下表所示:

成员含义
e_identMagic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32、ELF64
Data:2’s complement, little end
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
e_typeType: REL、EXEC、DYN ELF文件类型
e_machineMachine: ARM、AARCH64
e_versionVersion: 0x1 ELF版本号。一般为常数1
e_entryEntry point address: 0x0 入口地址,规定ELF程序的入口虚拟地址,操作系统在加载完该程序后从这个地址开始执行进程的指令。可重定位指令一般没有入口地址,则该值为0
e_phoffStart of program headers: 0(bytes into file)
e_shoffStart of section headers: 672 (bytes into file) Section Header Table 在文件中的偏移
e_wordFlags: 0x0 ELF标志位,用来标识一些ELF文件平台相关的属性。
e_ehsizeSize of this header: 64 (bytes) ELF Header本身的大小
e_phentsizeSize of program headers: 0 (bytes)
e_phnumNumber of program headers: 0
e_shentsizeSize of section headers: 64 (bytes) 单个Section Header大小
e_shnumNumber of section headers: 13 Section Header的数量
e_shstrndxSection header string table index: 10 Section Header字符串表在Section Header Table中的索引

ELF魔数

每种可执行文件的格式的开头几个字节都是很特殊的,特别是开头4个字节,通常被称为魔数(Magic Number)。通过对魔数的判断可以确定文件的格式和类型。如:ELF的可执行文件格式的头4个字节为0x7F、e、l、f;Java的可执行文件格式的头4个字节为c、a、f、e;如果被执行的是Shell脚本或perl、python等解释型语言的脚本,那么它的第一行往往是#!/bin/sh或#!/usr/bin/perl或#!/usr/bin/python,此时前两个字节#和!就构成了魔数,系统一旦判断到这两个字节,就对后面的字符串进行解析,以确定具体的解释程序路径。

ELF文件类型

ELF文件主要有三种类型,可以通过ELF Header中的e_type成员进行区分。

  • 可重定位文件(Relocatable File):REL。一般为.o文件。可以被链接成可执行文件或共享目标文件。静态链接库属于可重定位文件。
  • 可执行文件(Executable File):EXEC。可以直接执行的程序。
  • 共享目标文件(Shared Object File):DYN。一般为.so文件。有两种情况可以使用。
    链接器将其与其他可重定位文件、共享目标文件链接成新的目标文件;
    动态链接器将其与其他共享目标文件、结合一个可执行文件,创建进程映像。
    在这里插入图片描述

2. ELF Program Header Table

程序加载的时候,会以段(Segment)作为管理单位,比如虚拟内存地址映射。
注意:段(Segment)与节(Section)的区别。很多地方对两者有所混淆。段是程序执行的必要组成,当多个目标文件链接成一个可执行文件时,会将相同权限的节合并到一个段中。相比而言,节的粒度更小。下面是Section到Segement映射:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  EXIDX          0x00049c 0x0001049c 0x0001049c 0x00008 0x00008 R   0x4
  PHDR           0x000034 0x00010034 0x00010034 0x00120 0x00120 R   0x4
  INTERP         0x000154 0x00010154 0x00010154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.3]
  LOAD           0x000000 0x00010000 0x00010000 0x004a8 0x004a8 R E 0x10000
  LOAD           0x000f10 0x00020f10 0x00020f10 0x00118 0x0011c RW  0x10000
  DYNAMIC        0x000f18 0x00020f18 0x00020f18 0x000e8 0x000e8 RW  0x4
  NOTE           0x000168 0x00010168 0x00010168 0x00044 0x00044 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x000f10 0x00020f10 0x00020f10 0x000f0 0x000f0 R   0x1
 Section to Segment mapping:
  Segment Sections...
   00     .ARM.exidx
   01
   02     .interp
   03     .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .ARM.exidx .eh_frame
   04     .init_array .fini_array .dynamic .got .data .bss
   05     .dynamic
   06     .note.gnu.build-id .note.ABI-tag
   07
   08     .init_array .fini_array .dynamic
typedef struct {
  unsigned char	p_type[4];		/* Identifies program segment type */
  unsigned char	p_offset[4];		/* Segment file offset */
  unsigned char	p_vaddr[4];		/* Segment virtual address */
  unsigned char	p_paddr[4];		/* Segment physical address */
  unsigned char	p_filesz[4];		/* Segment size in file */
  unsigned char	p_memsz[4];		/* Segment size in memory */
  unsigned char	p_flags[4];		/* Segment flags */
  unsigned char	p_align[4];		/* Segment alignment, file & memory */
} Elf32_External_Phdr;

3. ELF Section Header Table

ELF 节头表是一个节头数组。每一个节头都描述了其所对应的节的信息,如节名、节大小、在文件中的偏移、读写权限等。编译器、链接器、装载器都是通过节头表来定位和访问各个节的属性的。

我们可以使用readelf -S工具来查看节头表。

root@DESKTOP-90KJ7MS:/usr/src/helloworld# readelf -S hello
There are 29 section headers, starting at offset 0x1ad8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        00010154 000154 000013 00   A  0   0  1
  [ 2] .note.gnu.build-i NOTE            00010168 000168 000024 00   A  0   0  4
  [ 3] .note.ABI-tag     NOTE            0001018c 00018c 000020 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        000101ac 0001ac 00002c 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          000101d8 0001d8 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          00010228 000228 000041 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0001026a 00026a 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         00010274 000274 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             00010294 000294 000008 08   A  5   0  4
  [10] .rel.plt          REL             0001029c 00029c 000020 08  AI  5  21  4
  [11] .init             PROGBITS        000102bc 0002bc 00000c 00  AX  0   0  4
  [12] .plt              PROGBITS        000102c8 0002c8 000044 04  AX  0   0  4
  [13] .text             PROGBITS        0001030c 00030c 000174 00  AX  0   0  4
  [14] .fini             PROGBITS        00010480 000480 000008 00  AX  0   0  4
  [15] .rodata           PROGBITS        00010488 000488 000011 00   A  0   0  4
  [16] .ARM.exidx        ARM_EXIDX       0001049c 00049c 000008 00  AL 13   0  4
  [17] .eh_frame         PROGBITS        000104a4 0004a4 000004 00   A  0   0  4
  [18] .init_array       INIT_ARRAY      00020f10 000f10 000004 04  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      00020f14 000f14 000004 04  WA  0   0  4
  [20] .dynamic          DYNAMIC         00020f18 000f18 0000e8 08  WA  6   0  4
  [21] .got              PROGBITS        00021000 001000 000020 04  WA  0   0  4
  [22] .data             PROGBITS        00021020 001020 000008 00  WA  0   0  4
  [23] .bss              NOBITS          00021028 001028 000004 00  WA  0   0  1
  [24] .comment          PROGBITS        00000000 001028 00002b 01  MS  0   0  1
  [25] .ARM.attributes   ARM_ATTRIBUTES  00000000 001053 00002a 00      0   0  1
  [26] .symtab           SYMTAB          00000000 001080 000660 10     27  80  4
  [27] .strtab           STRTAB          00000000 0016e0 0002f2 00      0   0  1
  [28] .shstrtab         STRTAB          00000000 0019d2 000105 00      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),
  y (purecode), p (processor specific)

ELF文件结构示意图中定义的Elf_Shdr的各个成员的含义与readelf具有对应关系。如下表所示:

成员含义
sh_name节名 节名是一个字符串,保存在一个名为.shstrtab的字符串表(可通过Section Header索引到)。sh_name的值实际上是其节名字符串在.shstrtab中的偏移值
sh_type节类型
sh_flags节标志位
sh_addr节地址:节的虚拟地址 如果该节可以被加载,则sh_addr为该节被加载后在进程地址空间中的虚拟地址;否则sh_addr为0
sh_offset节偏移 如果该节存在于文件中,则表示该节在文件中的偏移;否则无意义,如sh_offset对于BSS 节来说是没有意义的
sh_size节大小
sh_link、sh_info节链接信息
sh_addralign节地址对齐方式
sh_entsize节项大小 有些节包含了一些固定大小的项,如符号表,其包含的每个符号所在的大小都一样的,对于这种节,sh_entsize表示每个项的大小。如果为0,则表示该节不包含固定大小的项。

节类型(sh_type)相关常量以SHT_开头,上述readelf -S命令执行的结果省略了该前缀。常见的节类型如下表所示:

常量含义
SHT_NULL0无效节
SHT_PROGBITS1程序节。代码节、数据节都是这种类型。
SHT_SYMTAB2符号表
SHT_STRTAB3字符串表
SHT_RELA4重定位表。该节包含了重定位信息。
SHT_HASH5符号表的哈希表
SHT_DYNAMIC6动态链接信息
SHT_NOTE7提示性信息
SHT_NOBITS8表示该节在文件中没有内容。如.bss节
SHT_REL9该节包含了重定位信息
SHT_SHLIB10保留
SHT_DNYSYM11动态链接的符号表

节标志位(sh_flag)
节标志位表示该节在进程虚拟地址空间中的属性。如是否可写、是否可执行等。相关常量以SHF_开头。常见的节标志位如下表所示:

常量含义
SHF_WRITE1表示该节在进程空间中可写
SHF_ALLOC2表示该节在进程空间中需要分配空间。有些包含指示或控制信息的节不需要在进程空间中分配空间,就不会有这个标志。
SHF_EXECINSTR4表示该节在进程空间中可以被执行

节链接信息(sh_link、sh_info)
如果节的类型是与链接相关的(无论是动态链接还是静态链接),如重定位表、符号表、等,则sh_link、sh_info两个成员所包含的意义如下所示。其他类型的节,这两个成员没有意义。

sh_typesh_linksh_info
SHT_DYNAMIC该节所使用的字符串表在节头表中的下标0
SHT_HASH该节所使用的符号表在节头表中的下标0
SHT_REL该节所使用的相应符号表在节头表中的下标该重定位表所作用的节在节头表中的下标
SHT_RELA该节所使用的相应符号表在节头表中的下标该重定位表所作用的节在节头表中的下标
SHT_SYMTAB操作系统相关操作系统相关
SHT_DYNSYM操作系统相关操作系统相关
otherSHN_UNDEF0

4.ELF Sections

节的分类
上述ELF Section Header Table部分已经简单介绍了节类型。接下来我们来介绍详细一些比较重要的节。

.text节
.text节是保存了程序代码指令的代码节。一段可执行程序,如果存在Phdr,则.text节就会存在于text段中。由于.text节保存了程序代码,所以节类型为SHT_PROGBITS。

.rodata节
rodata节保存了只读的数据,如一行C语言代码中的字符串。由于.rodata节是只读的,所以只能存在于一个可执行文件的只读段中。因此,只能在text段(不是data段)中找到.rodata节。由于.rodata节是只读的,所以节类型为SHT_PROGBITS。

.plt节(过程链接表)
.plt节也称为过程链接表(Procedure Linkage Table),其包含了动态链接器调用从共享库导入的函数所必需的相关代码。由于.plt节保存了代码,所以节类型为SHT_PROGBITS。

.data节
.data节存在于data段中,其保存了初始化的全局变量等数据。由于.data节保存了程序的变量数据,所以节类型为SHT_PROGBITS。

.bss节
.bss节存在于data段中,占用空间不超过4字节,仅表示这个节本省的空间。.bss节保存了未进行初始化的全局数据。程序加载时数据被初始化为0,在程序执行期间可以进行赋值。由于.bss节未保存实际的数据,所以节类型为SHT_NOBITS。

.got.plt节(全局偏移表-过程链接表)
.got节保存了全局偏移表。.got节和.plt节一起提供了对导入的共享库函数的访问入口,由动态链接器在运行时进行修改。由于.got.plt节与程序执行有关,所以节类型为SHT_PROGBITS。

.dynsym节(动态链接符号表)
.dynsym节保存在text段中。其保存了从共享库导入的动态符号表。节类型为SHT_DYNSYM。

.dynstr节(动态链接字符串表)
.dynstr保存了动态链接字符串表,表中存放了一系列字符串,这些字符串代表了符号名称,以空字符作为终止符。

.rel.*节(重定位表)
重定位表保存了重定位相关的信息,这些信息描述了如何在链接或运行时,对ELF目标文件的某部分或者进程镜像进行补充或修改。由于重定位表保存了重定位相关的数据,所以节类型为SHT_REL。

.hash节
.hash节也称为.gnu.hash,其保存了一个用于查找符号的散列表。

.symtab节(符号表)
.symtab节是一个ElfN_Sym的数组,保存了符号信息。节类型为SHT_SYMTAB。

.strtab节(字符串表)
.strtab节保存的是符号字符串表,表中的内容会被.symtab的ElfN_Sym结构中的st_name引用。节类型为SHT_STRTAB。

.ctors节和.dtors节
.ctors(构造器)节和.dtors(析构器)节分别保存了指向构造函数和析构函数的函数指针,构造函数是在main函数执行之前需要执行的代码;析构函数是在main函数之后需要执行的代码。

符号表
节的分类中我们介绍了.dynsym节和.symtab节,两者都是符号表。那么它们到底有什么区别呢?存在什么关系呢?

符号是对某些类型的数据或代码(如全局变量或函数)的符号引用,函数名或变量名就是符号名。例如,printf()函数会在动态链接符号表.dynsym中存有一个指向该函数的符号项(以Elf_Sym数据结构表示)。在大多数共享库和动态链接可执行文件中,存在两个符号表。即.dynsym和.symtab。

.dynsym保存了引用来自外部文件符号的全局符号。如printf库函数。.dynsym保存的符号是.symtab所保存符合的子集,.symtab中还保存了可执行文件的本地符号。如全局变量,代码中定义的本地函数等。

既然.dynsym是.symtab的子集,那为何要同时存在两个符号表呢?

通过readelf -S命令可以查看可执行文件的输出,一部分节标志位(sh_flags)被标记为了A(ALLOC)、WA(WRITE/ALLOC)、AX(ALLOC/EXEC)。其中,.dynsym被标记为ALLOC,而.symtab则没有标记。

ALLOC表示有该标记的节会在运行时分配并装载进入内存,而.symtab不是在运行时必需的,因此不会被装载到内存中。.dynsym保存的符号只能在运行时被解析,因此是运行时动态链接器所需的唯一符号。.dynsym对于动态链接可执行文件的执行是必需的,而.symtab只是用来进行调试和链接的。
在这里插入图片描述

上图所示为通过符号表索引字符串表的示意图。符号表中的每一项都是一个Elf_Sym结构,对应可以在字符串表中索引得到一个字符串。该数据结构中成员的含义如下表所示:

成员 含义
st_name 符号名。该值为该符号名在字符串表中的偏移地址。
st_value 符号对应的值。存放符号的值(可能是地址或位置偏移量)。
st_size 符号的大小。
st_other 0
st_shndx 符号所在的节
st_info 符号类型及绑定属性
使用readelf工具我们也能够看到符号表的相关信息。

root@DESKTOP-90KJ7MS:/usr/src/helloworld# readelf -s hello

Symbol table '.dynsym' contains 5 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.4 (2)
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort@GLIBC_2.4 (2)
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.4 (2)

Symbol table '.symtab' contains 102 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00010154     0 SECTION LOCAL  DEFAULT    1
     2: 00010168     0 SECTION LOCAL  DEFAULT    2
     3: 0001018c     0 SECTION LOCAL  DEFAULT    3
     4: 000101ac     0 SECTION LOCAL  DEFAULT    4
     5: 000101d8     0 SECTION LOCAL  DEFAULT    5
     6: 00010228     0 SECTION LOCAL  DEFAULT    6
     7: 0001026a     0 SECTION LOCAL  DEFAULT    7
     8: 00010274     0 SECTION LOCAL  DEFAULT    8
     9: 00010294     0 SECTION LOCAL  DEFAULT    9
    10: 0001029c     0 SECTION LOCAL  DEFAULT   10
    11: 000102bc     0 SECTION LOCAL  DEFAULT   11
    12: 000102c8     0 SECTION LOCAL  DEFAULT   12
    13: 0001030c     0 SECTION LOCAL  DEFAULT   13
    14: 00010480     0 SECTION LOCAL  DEFAULT   14
    15: 00010488     0 SECTION LOCAL  DEFAULT   15
    16: 0001049c     0 SECTION LOCAL  DEFAULT   16
    17: 000104a4     0 SECTION LOCAL  DEFAULT   17
    18: 00020f10     0 SECTION LOCAL  DEFAULT   18
    19: 00020f14     0 SECTION LOCAL  DEFAULT   19
    20: 00020f18     0 SECTION LOCAL  DEFAULT   20
    21: 00021000     0 SECTION LOCAL  DEFAULT   21
    22: 00021020     0 SECTION LOCAL  DEFAULT   22
    23: 00021028     0 SECTION LOCAL  DEFAULT   23
    24: 00000000     0 SECTION LOCAL  DEFAULT   24
    25: 00000000     0 SECTION LOCAL  DEFAULT   25
    26: 00000000     0 FILE    LOCAL  DEFAULT  ABS /usr/lib/gcc-cross/arm-li
    27: 0001018c     0 NOTYPE  LOCAL  DEFAULT    3 $d
    28: 0001030c     0 NOTYPE  LOCAL  DEFAULT   13 $a
    29: 0001049c     0 NOTYPE  LOCAL  DEFAULT   16 $d
    30: 0001033c     0 NOTYPE  LOCAL  DEFAULT   13 $d
    31: 00010488     0 NOTYPE  LOCAL  DEFAULT   15 $d
    32: 00021020     0 NOTYPE  LOCAL  DEFAULT   22 $d
    33: 00000000     0 FILE    LOCAL  DEFAULT  ABS /usr/lib/gcc-cross/arm-li
    34: 00010348     0 NOTYPE  LOCAL  DEFAULT   13 $a
    35: 00010348     0 FUNC    LOCAL  DEFAULT   13 call_weak_fn
    36: 00010364     0 NOTYPE  LOCAL  DEFAULT   13 $d
    37: 000102bc     0 NOTYPE  LOCAL  DEFAULT   11 $a
    38: 00010480     0 NOTYPE  LOCAL  DEFAULT   14 $a
    39: 00000000     0 FILE    LOCAL  DEFAULT  ABS /usr/lib/gcc-cross/arm-li
    40: 000102c4     0 NOTYPE  LOCAL  DEFAULT   11 $a
    41: 00010484     0 NOTYPE  LOCAL  DEFAULT   14 $a
    42: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    43: 0001036c     0 NOTYPE  LOCAL  DEFAULT   13 $a
    44: 0001036c     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    45: 0001038c     0 NOTYPE  LOCAL  DEFAULT   13 $d
    46: 00010398     0 NOTYPE  LOCAL  DEFAULT   13 $a
    47: 00010398     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    48: 000103c4     0 NOTYPE  LOCAL  DEFAULT   13 $d
    49: 00021024     0 NOTYPE  LOCAL  DEFAULT   22 $d
    50: 000103d0     0 NOTYPE  LOCAL  DEFAULT   13 $a
    51: 000103d0     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    52: 000103f4     0 NOTYPE  LOCAL  DEFAULT   13 $d
    53: 00021028     1 OBJECT  LOCAL  DEFAULT   23 completed.10172
    54: 00020f14     0 NOTYPE  LOCAL  DEFAULT   19 $d
    55: 00020f14     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fin
    56: 000103f8     0 NOTYPE  LOCAL  DEFAULT   13 $a
    57: 000103f8     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    58: 00020f10     0 NOTYPE  LOCAL  DEFAULT   18 $d
    59: 00020f10     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_
    60: 00021028     0 NOTYPE  LOCAL  DEFAULT   23 $d
    61: 00000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    62: 0001048c     0 NOTYPE  LOCAL  DEFAULT   15 $d
    63: 000103fc     0 NOTYPE  LOCAL  DEFAULT   13 $a
    64: 00010418     0 NOTYPE  LOCAL  DEFAULT   13 $d
    65: 00000000     0 FILE    LOCAL  DEFAULT  ABS elf-init.oS
    66: 0001041c     0 NOTYPE  LOCAL  DEFAULT   13 $a
    67: 00010474     0 NOTYPE  LOCAL  DEFAULT   13 $d
    68: 0001047c     0 NOTYPE  LOCAL  DEFAULT   13 $a
    69: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    70: 000104a4     0 NOTYPE  LOCAL  DEFAULT   17 $d
    71: 000104a4     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    72: 00000000     0 FILE    LOCAL  DEFAULT  ABS
    73: 00020f14     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    74: 00020f18     0 OBJECT  LOCAL  DEFAULT   20 _DYNAMIC
    75: 00020f10     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    76: 00021000     0 OBJECT  LOCAL  DEFAULT   21 _GLOBAL_OFFSET_TABLE_
    77: 000102c8     0 NOTYPE  LOCAL  DEFAULT   12 $a
    78: 000102d8     0 NOTYPE  LOCAL  DEFAULT   12 $d
    79: 000102dc     0 NOTYPE  LOCAL  DEFAULT   12 $a
    80: 0001047c     4 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    81: 00021020     0 NOTYPE  WEAK   DEFAULT   22 data_start
    82: 00021028     0 NOTYPE  GLOBAL DEFAULT   23 __bss_start__
    83: 0002102c     0 NOTYPE  GLOBAL DEFAULT   23 _bss_end__
    84: 00021028     0 NOTYPE  GLOBAL DEFAULT   22 _edata
    85: 00010480     0 FUNC    GLOBAL HIDDEN    14 _fini
    86: 0002102c     0 NOTYPE  GLOBAL DEFAULT   23 __bss_end__
    87: 00021020     0 NOTYPE  GLOBAL DEFAULT   22 __data_start
    88: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.4
    89: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    90: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    91: 00021024     0 OBJECT  GLOBAL HIDDEN    22 __dso_handle
    92: 00010488     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    93: 0001041c    96 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    94: 0002102c     0 NOTYPE  GLOBAL DEFAULT   23 _end
    95: 0001030c     0 FUNC    GLOBAL DEFAULT   13 _start
    96: 0002102c     0 NOTYPE  GLOBAL DEFAULT   23 __end__
    97: 00021028     0 NOTYPE  GLOBAL DEFAULT   23 __bss_start
    98: 000103fc    32 FUNC    GLOBAL DEFAULT   13 main
    99: 00021028     0 OBJECT  GLOBAL HIDDEN    22 __TMC_END__
   100: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort@@GLIBC_2.4
   101: 000102bc     0 FUNC    GLOBAL HIDDEN    11 _init

字符串表
类似于符号表,在大多数共享库和动态链接可执行文件中,也存在两个字符串表。即.dynstr和.strtab,分别对应于.dynsym和symtab。此外,还有一个.shstrtab的节头字符串表,用于保存节头表中用到的字符串,可通过sh_name进行索引。

ELF文件中所有字符表的结构基本一致,如上图所示。

重定位表
重定位就是将符号定义和符号引用进行连接的过程。可重定位文件需要包含描述如何修改节内容的相关信息,从而使可执行文件和共享目标文件能够保存进程的程序镜像所需要的正确信息。

重定位表是进行重定位的重要依据。我们可以使用objdump工具查看目标文件的重定位表:

root@DESKTOP-90KJ7MS:/usr/src/helloworld# readelf -r hello

Relocation section '.rel.dyn' at offset 0x294 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
0002101c  00000115 R_ARM_GLOB_DAT    00000000   __gmon_start__

Relocation section '.rel.plt' at offset 0x29c contains 4 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0002100c  00000216 R_ARM_JUMP_SLOT   00000000   puts@GLIBC_2.4
00021010  00000416 R_ARM_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.4
00021014  00000116 R_ARM_JUMP_SLOT   00000000   __gmon_start__
00021018  00000316 R_ARM_JUMP_SLOT   00000000   abort@GLIBC_2.4

重定位表是一个Elf_Rel类型的数组结构,每一项对应一个需要进行重定位的项。 其成员含义如下表所示:

成员 含义
r_offset 重定位入口的偏移。
对于可重定位文件来说,这个值是该重定位入口所要修正的位置的第一个字节相对于节起始的偏移
对于可执行文件或共享对象文件来说,这个值是该重定位入口所要修正的位置的第一个字节的虚拟地址
r_info 重定位入口的类型和符号
因为不同处理器的指令系统不一样,所以重定位所要修正的指令地址格式也不一样。每种处理器都有自己的一套重定位入口的类型。
对于可执行文件和共享目标文件来说,它们的重定位入口是动态链接类型的。
重定位是目标文件链接成为可执行文件的关键。我们将在后面的进行介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2401845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DisplayPort 2.0协议介绍(1)

最近开始学习DisplayPort 2.0协议,相比于DP1.4a,最主要的是速率提升到了10Gbps/lane,还有就是128b/132b编码方式的修改。至于速率13.5Gbps和20Gbps还只是可选项,在DP2.1协议才成为必须支持选项。 那在实现技术细节上有哪些变化呢…

I2C通信讲解

I2C总线发展史 怎么在一条串口线上连接多个设备呢? 由于速度同步线是由主机实时发出的,所以主机可以按需求修改通信速度,这样在一条线上可以挂接不同速度的器件,单片机和性能差的器件通信,就输出较慢的脉冲信号&#x…

基于回归算法的心理健康预测(EDA + 预测)

心理健康涵盖情感、心理与社会福祉,影响认知、情绪和行为模式,决定压力应对、人际交往及健康决策,且在生命各阶段(从童年至成年)均至关重要。心理健康与身体健康同为整体健康的核心要素:抑郁会增加糖尿病、…

【新品解读】一板多能,AXRF49 定义新一代 RFSoC FPGA 开发平台

“硬件系统庞杂、调试周期长” “高频模拟前端不稳定,影响采样精度” “接收和发射链路难以同步,难以扩展更多通道” “数据流量大,处理与存储跟不上” 这些是大部分客户在构建多通道、高频宽的射频采样链路时,面临的主要问题。…

贪心算法应用:线性规划贪心舍入问题详解

贪心算法应用:线性规划贪心舍入问题详解 贪心算法是一种在每一步选择中都采取当前状态下最优的选择,从而希望导致结果是全局最优的算法策略。在线性规划问题中,贪心算法特别是贪心舍入技术有着广泛的应用。下面我将全面详细地讲解这一主题。…

YOLO在C#中的完整训练、验证与部署方案

YOLO在C#中的完整训练、验证与部署方案 C# 在 YOLO 部署上优势明显(高性能、易集成),但训练能力较弱,通常需结合 Python 实现。若项目对开发效率要求高且不依赖 C# 生态,建议全程使用 Python;若需深度集成…

洛谷题目:P2761 软件补丁问题 (本题简单)

个人介绍: 题目传送门: P2761 软件补丁问题 - 洛谷 (luogu.com.cn) 前言: 这道题是一个典型的状态搜索问题,核心目标就是利用给定d额多个补丁程序,将包含若干错误的软件修复成没有错误的状态,并且要使得修复过程当中的总耗时最少。下面是小亦为大家阐述滴思路: 1、状态…

智慧园区数字孪生全链交付方案:降本增效30%,多案例实践驱动全周期交付

在智慧园区建设浪潮中,数字孪生技术正成为破解传统园区管理难题的核心引擎。通过构建与物理园区1:1映射的数字模型,实现数据集成、状态同步与智能决策,智慧园区数字孪生全链交付方案已在多个项目中验证其降本增效价值——某物流园区通过该方案…

【OpenGL学习】(四)统一着色和插值着色

文章目录 【OpenGL学习】(四)统一着色和插值着色统一着色(Flat/Uniform Shading)插值着色(Interpolated Shading) 【OpenGL学习】(四)统一着色和插值着色 着色器介绍: h…

在 CentOS 上安装 Docker 和 Docker Compose 并配置使用国内镜像源

在 CentOS 上安装 Docker 和 Docker Compose 并配置使用国内镜像源,可以加速镜像下载速度。以下是详细的步骤: 一、安装 Docker 移除旧版本的 Docker(如果有): sudo yum remove docker \docker-client \docker-client…

Docker慢慢学

1、Docker DeskTop 2、N8N下载 docker run -p 8888:5678 n8nio/n8n 3、Kafka kafka依赖zookeeper,先启动zookeeper docker pull zookeeper docker run -d --name zookeeper -p 2181:2181 -e ALLOW_ANONYMOUS_LOGINyes zookeeper 启动kafka docker pull confluentinc/cp…

cursor-free-vip使用

一、项目简介 Cursor-Free-VIP 是一个开源项目,旨在帮助用户免费使用 Cursor AI 的高级功能。它通过自动注册 Cursor 账号、重置机器 ID 和完成 Auth 验证等操作,解决 Cursor AI 中常见的限制提示。 二、系统准备 1…cursor需要更新到最新的版本 三、…

使用SSH tunnel访问内网的MySQL

文章目录 环境背景方法参考 注:本文是使用SSH tunnel做端口转发的一个示例。有关SSH端口转发,可参考我的几篇文档 https://blog.csdn.net/duke_ding2/article/details/106878081https://blog.csdn.net/duke_ding2/article/details/135627263https://blo…

Redis持久化模式RDB与AOF

RDB持久化 RDB也被叫做Redis数据快照。简单来说就是把内存中的所有数据记录到磁盘中。当Redis实例故障重启后重磁盘中读取快照文件进行数据恢复(快照文件默认保存在当前运行目录); 演示Redis正常停机自动执行一次RDB操作 配置Redis触发RDB机制 RDB其它配置也可在red…

【数据结构】树形结构--二叉树(二)

【数据结构】树形结构--二叉树(二) 一.二叉树的实现1.求二叉树结点的个数2.求二叉树叶子结点的个数3.求二叉树第k层结点的个数4.求二叉树的深度(高度)5.在二叉树中查找值为x的结点6.判断二叉树是否为完全二叉树7.二叉树的销毁 一.…

深度学习题目1

梯度下降法的正确步骤是什么? a.计算预测值和真实值之间的误差 b.重复迭代,直至得到网络权重的最佳值 c.把输入传入网络,得到输出值 d.用随机值初始化权重和偏差 e.对每一个产生误差的神经元,调整相应的(权重&#xff…

【Oracle】锁

个人主页:Guiat 归属专栏:Oracle 文章目录 1. 锁基础概述1.1 锁的概念与作用1.2 锁的工作原理1.3 Oracle锁的分类 2. 行级锁 (Row-Level Locks)2.1 行级锁的基本概念2.1.1 TX锁(事务锁)2.1.2 行级锁的工作机制 2.2 行级锁的类型2.…

JS逆向爬虫教程与实战技巧

想要一个关于爬虫JS逆向的详细教程。这是一个很专业的技术需求,最近有个可能是正在学习爬虫技术的开发者或者数据分析师,遇到了需要破解JavaScript加密的反爬机制的问题,想让我出一期实战教程,话不多说,开干。 以下是我…

【Redis】Redis 的常见客户端汇总

目录 一、命令行客户端 二、图形界面的客户端 三、Java 客户端 3.1 SpringDataRedis 3.2 Jedis 3.2.1 连接池的配置 3.3 Lettuce 3.3.1 RedisTemplate 工具类实现 3.3.2 自定义序列化器 3.3.3 StringRedisTemplate 3.3.4 集群配置 3.3.4.1 刷新节点集群拓扑动态感应…

关于akka官方quickstart示例程序(scala)的记录

参考资料 https://doc.akka.io/libraries/akka-core/current/typed/actors.html#first-example 关于scala语法的注意事项 extends App是个语法糖,等同于直接在伴生对象中编写main 方法对象是通过apply方法创建的,也可以通过对象的名称单独创建&#x…