ELF格式文件说明

简介:

Linux可执行文件为ELF格式,ELF格式文件主要分为以下几类:
1. 可重定位文件(Relocatable File),这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库也可以归为这一类,如.o文件。

2. 可执行文件(Executable File),这类文件包含了直接执行的程序,如/bin/bash等。

3. 共享目标文件(Shared Object File),链接器可以使用这种文件跟其他的可重定位文件和共享目标文件链接,产生新的目标文件;动态链接器可以将几个共享目标文件与可执行文件结合,作为进程映像的一部分来运行,如glibc*.so。

4. 核心转储文件(Core Dump File),当进程意外终止时,系统可以将该进程的地址空间内容及终止时的一些其他信息转储到核心转储文件。
image
如 上图所示,目标文件的开头是一个文件头,它描述了整个文件的文件属性,包括文件是否可执行,是静态链接还是动态链接及入口地址(如果 是可执行文件),目标硬件,目标操作系统的信息。文件头还包括一个段表,段表其实是一个描述文件中各个段的数组。段表描述了文件中各个段在文件中的偏移位 置及段的属性等。文件头后面就是各个段的内容,如代码段保存的是程序的指令,数据段保存的是程序里的一些变量等。

程序指令与数据分离成不同段的原因:

1. 当程序被装载后,数据和指令分别被映射到两个虚存区域。由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写和只读。这样可以防止程序的指令被有意或无意地改写。

2. 对于现代的CPU来说,它们有着极为强大的缓存(Cache)体系。由于缓存在现代的计算机中地位非常重要,所以程序必须尽量提高缓存的命中率。指令区和数据区的分离有利于提高程序的局部性。现代CPU的缓存一般都被设计成数据缓存和指令缓存分离,所以程序的指令和数据被分开存放对CPU的缓存命中率提高有好处。

3. 也 是最重要的原因,就是当系统中运行着多个该程序的副本时,它们的指令都是一样的,所以内存中只须要保存一份改程序的指令部分。对于指令这种只读的区域来说 是这样,对于其他的只读数据也一样,比如很多程序里面带有的图标、图片、文本等资源也是属于可以共享的。当然每个副本进程的数据区域是不一样的,它们是进 程私有的。

ELF文件中常见的段
image
文件头

文件头的结构定义如下所示:

typedef struct {

unsigned char e_ident[16]; 

Elf32_Half e_type;        

Elf32_Half e_machine;    

Elf32_Word e_version;    

Elf32_Addr e_entry;      

Elf32_Off  e_phoff;      

Elf32_Off  e_shoff;       
Elf32_Word e_flags;      
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;

可通过readelf –h hello.o来查看ELF文件的文件头

 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:                         Intel 80386

  Version:                          0x1

  Entry point address:                0x0

  Start of program headers:            0 (bytes into file)

  Start of section headers:             220 (bytes into file)

  Flags:                             0x0

  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:         11

  Section header string table index:     8

l 段表

ELF文件中有很多段,段表就是保存这些段的基本属性的结构。段表是ELF文件中出文件头以为最重要的结构,它描述了ELF的各个段的信息,如每个段的名字,段的长度,在文件中的偏移,读写权限等。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;

可通过readelf –S *.o来查看ELF文件的段表

There are 11 section headers, starting at offset 0xdc:

 

Section Headers:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                   NULL            00000000 000000 000000 00      0   0  0

  [ 1] .text             PROGBITS        00000000 000034 00001c 00  AX  0   0  4

  [ 2] .rel.text         REL             00000000 000348 000010 08      9   1  4

  [ 3] .data             PROGBITS        00000000 000050 000000 00  WA  0   0  4

  [ 4] .bss              NOBITS          00000000 000050 000000 00  WA  0   0  4

  [ 5] .rodata           PROGBITS        00000000 000050 00000c 00   A  0   0  1

  [ 6] .comment          PROGBITS        00000000 00005c 00002d 00      0   0  1

  [ 7] .note.GNU-stack   PROGBITS        00000000 000089 000000 00      0   0  1

  [ 8] .shstrtab         STRTAB          00000000 000089 000051 00      0   0  1

  [ 9] .symtab           SYMTAB          00000000 000294 0000a0 10     10   8  4

  [10] .strtab           STRTAB          00000000 000334 000013 00      0   0  1

Key to Flags:

W (write), A (alloc), X (execute), M (merge), S (strings)

I (info), L (link order), G (group), x (unknown)

O (extra OS processing required) o (OS specific), p (processor specific)

l 重定位表

从上面的输出可以看到,ELF文件中包含.rel.text的段,它是一个重定位表。链接器在处理目标文件时,需要对目标文件中某些部位进行重定位,及代码段和数据段中那些对绝对地址引用的位置。这些重定位的信息都记录在ELF文件的重定位表里面,对于每个需要重定位的代码段或数据段,都会有相应的重定位表。

l 字符串表

ELF文件中用到了很多字符串,比如段名,变量名等。因为字符串的长度往往不是固定的,故难以用固定的结构表示。常见的做法是把字符串集中起来存放到一个表,然后使用字符串在表中的偏移来引用字符串。如下所示:
image

通过该方法,在ELF文件中引用字符串只需要给出一个数字下标(偏移)即可,如上表所示:偏移0对应空字符串,偏移1对应helloworld,偏移6对应world,偏移12对应myvariable等而不用考虑字符串的长度,字符串表在ELF文件中也以段的形式保存,如.strtab(字符串表), .shstrtab(段表字符串表),前者用来保存普通的字符串,如符号的名字;后者用来保存段表中用到的字符串如段名。

一个典型的ELF目标文件的结构如下图(转自51.com)所示:
image

目录
相关文章
|
设计模式 小程序 API
小程序之页面通信&派发通知
小程序之页面通信&派发通知
|
容器
Flutter 组件(一)组件概述
Flutter 组件(一)组件概述
693 0
|
6月前
|
机器学习/深度学习 监控 算法
基于YOLO26的电梯内电瓶车检测识别(中英文双版) | 附完整源码与效果演示
本文提出了一种基于YOLO26深度学习算法的电梯内电瓶车检测识别系统。该系统通过部署在电梯内的摄像头实时采集视频流,利用训练好的YOLO26模型对画面中的目标进行检测,准确识别出自行车和电动摩托车两类目标,从而实现对违规行为的智能预警和拦截。
|
5月前
|
机器学习/深度学习 人工智能 数据可视化
Geo优化新范式:深度解析知识图谱构建工具与“双核四驱”实战策略
在生成式AI重塑信息分发的今天,SEO正升级为Geo(生成式引擎优化)。本文详解Geo底层逻辑:以知识图谱为枢纽,融合Protégé建模、Neo4j图谱、BERT抽取与JSON-LD标记,结合于磊首创“两大核心+四轮驱动”体系,助力企业提升AI引用率与数字可见度。
377 9
|
5月前
|
Java 开发工具 Android开发
HarmonyOS鸿蒙应用备案高效获取公钥和证书MD5指纹的保姆级教程
本文详解鸿蒙应用(HarmonyOS Next)公钥与证书MD5指纹的三种获取方式:①通过AGC平台下载.cer证书后在线解析;②在AGC控制台直接复制“验证公钥”及已配置的证书指纹;③使用OpenSSL命令行本地提取(无需联网)。适用于ICP备案及第三方SDK接入场景,助力开发者快速完成配置。(239字)
1136 2
|
11月前
|
IDE 编译器 开发工具
Dev-C++ 6.5 安装与配置全攻略:零基础也能轻松搞定!
Dev-C++ 6.5 是一款轻量开源的C/C++集成开发环境,支持MinGW64/TDM-GCC编译器,兼容C++98至C++17标准,适用于Windows平台,安装简便,适合初学者快速上手编程。
1659 0
|
5月前
|
数据库 索引 Windows
搜索神器Everything官方下载:Windows最强文件搜索工具
Everything是一款2009年推出的Windows免费文件搜索工具,主打“输入即搜”极速体验。100万文件建索引仅需1分钟,搜索响应<1秒,远超系统自带搜索。支持通配符、正则、大小/时间筛选等高级语法,提供便携版与安装版,轻量高效,是文件检索利器。(239字)
|
存储 机器学习/深度学习 数据可视化
MATLAB脚本与函数
【10月更文挑战第4天】本文介绍了MATLAB脚本与函数的基本概念及编写方法,涵盖脚本和函数的创建、运行及优缺点,通过示例帮助初学者快速上手。同时,文章还涉及数据类型、控制结构、数据可视化、文件操作、错误处理等内容,提供了丰富的示例和学习资源,助力初学者逐步掌握MATLAB编程。
|
存储 API 索引
一文让你搞懂 Python 虚拟机执行字节码的奥秘
一文让你搞懂 Python 虚拟机执行字节码的奥秘
605 1
WK
|
机器学习/深度学习 算法
什么是损失函数和损失函数关于参数的梯度
损失函数是机器学习中评估模型预测与真实值差异的核心概念,差异越小表明预测越准确。常见损失函数包括均方误差(MSE)、交叉熵损失、Hinge Loss及对数损失等。通过计算损失函数关于模型参数的梯度,并采用梯度下降法或其变种(如SGD、Adam等),可以优化参数以最小化损失,提升模型性能。反向传播算法常用于神经网络中计算梯度。
WK
946 1