装载器-ELF文件分析【1】

ELF 文件格式解析

Linux 系统下的可执行文件、可重定位表和.so文件都是采用ELF格式存储。ELF格式起源于Unix的COFF文件格式。定义了各种段表结构体和存储方式。本文就这几个内容做一些介绍.

ELF 基本结构

   ELF的基本结构是由一个ELF文件头部和多个段所组成。文件头部包括了指明该ELF文件的相关信息。比如,头部信息可以表明该文件是可执行文件,还是可重定位表 or .so文件。头部之后就是各个段排列开来,例如.text段主要是代码段,编译后的代码一般存储在此段。.data段为数据段,数据段主要是存放初始化的全局静态变量、局部静态变量。实际上还有只读数据段.rodata,这个段一般存放一些常量,如字符串常量。.bss段则是那些未初始化的全局变量和局部静态变量存储的区域。当然,实际中,段的类型和数量远不止这几种这么多,甚至用户可以自己定义属于自己的段。后面会详述这些段的组织方式和结构。


ELF整体结构
ELF整体结构

一个通用的ELF整体结构图如下所示,注意这里的节区头部表指的就是段头部表( 这个表相当于一个数组,每一个元素用来描述相应段的属性例如段名、段长、段偏移等)

LD-HEADER

ELF 头部信息结构

ELF 最前面是ELF文件头(ELF-Header),它包括了描述整个文件的基本属性,如版本号、目标机器型号、程序入口地址等。ELF头中更重要的一部分是包括了对后面所有段描述的数组,该数组中的每一个元素包括了段的名字、长度、在文件中的偏移,读写权限及段的属性。
ELF Header:

Magic: xx  xx xx xx xx xx xx xx xx xx //魔数
Class: //ELF字长 ELF32,ELF64
Data: //数据存储方式
Version://版本号
OS/ABI://运行平台
ABI Version://ABI(application binary Interface)版本号
Type://ELF重定位类型
Machine://硬件平台 Intel x80386 x86_64 (是指芯片的型号与类型)
Version://硬件平台版本号
Entry point address://程序入口地址
Start of program headers://程序头入口 ??作用
Start of section headers://段头入口
Flags://
Size of this header:
Size of program headers:
Number of program headers:
Size of Section headers://段头长度
Number of section headers://段的数量
Section header string table index:

注意 这里magic 也就是魔数,ELF文件最前面的16个字节,它是用来代表ELF文件的平台属性、字长、字序、版本等相关信息。最开始的4个字节是所有ELF度必须相同的标识码即:7F 45 4C 46。魔数的作用是用来确认文件的类型,操作系统在加载可执行文件的时候会确认魔数是否正确,如果不正确会拒绝加载。

使用binutils 工具readelf 可以读到ELF文件的头部信息,例如下面的一个例子。这是一个在ARM平台上运行ELF文件

zhr-macox@laptop:/Project/Projects/iotsecurity$ readelf -a iot_app
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2s 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:               0x8a84
  Start of program headers:          52 (bytes into file)
  Start of section headers:          12780 (bytes into file)
  Flags:                             0x5000002, has entry point, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         10
  Size of section headers:           40 (bytes)//段头长度
  Number of section headers:         30 //一共30个段
  Section header string table index: 27

以上的头部信息对应的ELF头部结构体如下:

typedef struct {
unsigned char e_ident[16];  /* ELF魔数,ELF字长,字节序,ELF文件版本等 */
Elf32_Half e_type;         /*ELF文件类型,REL, 可执行文件,共享目标文件等 */
Elf32_Half e_machine;     /* ELF的CPU平台属性 */
Elf32_Word e_version;     /* ELF版本号 */
Elf32_Addr e_entry;       /* ELF程序的入口虚拟地址,REL一般没有入口地址为0 */
Elf32_Off  e_phoff;      
Elf32_Off  e_shoff;        /* 段表在文件中的偏移 */
Elf32_Word e_flags;       /* 用于标识ELF文件平台相关的属性 */
Elf32_Half e_ehsize;       /* 本文件头的长度 */
Elf32_Half e_phentsize;   
Elf32_Half e_phnum;
Elf32_Half e_shentsize;    /* 段表描述符的大小 */
Elf32_Half e_shnum;      /* 段表描述符的数量 */
Elf32_Half e_shstrndx;     /* 段表字符串表所在的段在段表中的下标 */
} Elf32_Ehdr;

其中的数据类型定义如下


ELF data type

ELF头部表中对段的描述

在ELF的头部中,有一部分是关于对段的描述,其中e_shoff代表了段头描述符表(Section Data Table,注意就是段头数组)的偏移位置,e_shentsize代表一个段头描述符的长度,e_shnum 代表该段头数组中元素的个数,也就是段的个数也就是说,通过这三个参数,可以获知该ELF文件中所有的段信息。在段头描述符表中,每个元素代表一个段的信息,也是一个结构体,这个结构体的描述如下;

typedef struct
{
Elf32_Word    sh_name;   /* 段的名字 */
Elf32_Word    sh_type;    /* 段的类型,代码段,数据段,符号表等 */
Elf32_Word    sh_flags;    /* 段在进程虚拟地址空间中的属性 */
Elf32_Addr    sh_addr;    /* 段的虚拟地址 */
Elf32_Off      sh_offset;   /* 段在文件中的偏移 */
Elf32_Word    sh_size;    /* 段的长度 */
Elf32_Word    sh_link;   
Elf32_Word    sh_info;
Elf32_Word    sh_addralign;  /* 段地址对齐 */
Elf32_Word    sh_entsize;
} Elf32;

由此可以知道,当一个ELF文件被载入的时候,加载器可以先读取ELF的头部信息,然后根据该头部信息可以获取段头部表的偏移,获取到段头部表后,可以接儿获知该ELF文件中的所有段信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值