使用readelf分析一个elf文件完整结构

article/2025/11/6 8:19:03

编译器编译源代码后生成的文件叫目标文件

从结构上来说与可执行文件一致,只是还没有经过动态链接的过程,有符号还没有被调整。与真正可执行文件稍有区别。

可执行文件格式涵盖了程序的编译、链接、装载和执行的各个方面。

windows下的PE和Linux下的ELF,都是COFF格式的变种。

目标文件(Linux下的.o win下的.obj)与可执行文件就差了个静态链接过程,一般存储格式是一样的,在Linux下为ELF文件。

动态链接库(DLL .dll和.so )以及静态链接库(Static Linking Library .lib和.a)也都是按照可执行文件格式存储的。

ELF文件类型

可重定位文件(Relocatable File)包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态库也可以归为此类

可执行文件(Executable File)ELF可执行文件

共享目标文件(Shared Object File)包含了代码和数据,两种情况:一种是静态链接器可以使用进行重定位产生新的目标文件,二是动态链接器

核心转储文件(Core Dump File)

COFF的主要贡献是在目标文件中引入段的机制,不同的目标文件可以拥有不同数量以及不同类型的段,另外还定义了调试数据格式。

目标文件内容

内容包括编译后的机器指令代码、数据,以及一些链接时需要的信息:符号表、调试信息、字符串等。按照不同的属性,以“节”的形式进行存储,有时候也称“段”。

文件头:File Header  (描述了整个文件的文件属性,包括文件是否可执行、是静态链接还是动态链接以及入口地址(如果是可执行文件)、目标硬件、目标操作系统 )

(段表:属于文件头中一部分,段表是一个描述文件中各个段的数组,描述了文件中各段在文件的偏移位置以及段的属性)

代码段:.code  .text   机器代码 汇编

数据段:.data   以及初始化的全局变量和局部静态变量

未初始化段: .bss 未初始化的全局变量和局部静态变量预留位置,  默认值为0, 在.data段中分配空间并存放数据0是没有必要的,elf文件中只是记录了需要分配内存的总和,该段不占用空间。

可执行文件必须记录所有全局变量和局部静态变量的大小总和。

BSS(Block Started by Symbol)

程序代码编译后主要分为两种段:程序指令和程序数据。代码段属于程序指令,而数据段和.bss段属于程序数据。

数据和指令分开的好处:1:读写权限;2:CPU cache缓存问题,提升cache命中率;3:指令可以复用。

----------------------------------------------------------------------------------------------

64位Ubuntu系统

代码示例

int printf(const char* format, ...);
int global_init_var = 84;
int global_uninit_var;
void func1(int i)
{printf("%d\n", i);
}
int main(void)
{static int static_var = 85;static int static_var2;int a = 1;int b;func1( static_var + static_var2 + a + b);return a;
}

gcc -c SimpleSection.c

objdump -h SimpleSection.o

 代码段、数据段、.bss段、只读数据段(.rodata)、注释信息段(.comment)和堆栈提示段(.note.GNU-stack)

size  SimpleSection.o

 objdump -s -d SimpleSection.o

一般而言bss是未初始化的全局变量和局部静态变量预留位置 ,这里有两个global_uninit_var和 static_var2,应该是8,实际才是4。实际这里只存了static_var2;

这跟强符号和弱符号有关系,global_uninit_var是等到最终链接成可执行文件时才在bss段分配标记。

自定义段:

有时候可能希望变量或者部分代码能够放到你所指定的段中去,以实现某些特定的功能。比如为了满足某些硬件的内存和I/O的地址布局,或者像Linux内核中用来完成一些初始化和用户空间复制时出现页错误异常等。

__attribute__((section("FOO"))) int global = 42;

在全局变量或函数之前加上“__attribute__((section("name")))”属性就可以把相应的变量或者函数放在以name作为段名的段中。

ELF文件的总体结构:

ELF Header

.text

.data

.bss

Other sections

Section header Table

String Tables

Symbol Tables

readelf -h 查看命令的帮助信息,需要正确区分文件头、section头、程序头(可执行程序才有)。

程序头是可执行程序load和exec时使用的,在汇编和链接过程中用不到;

相应的Section头在load时也用不上。

 ELF file Header : 描述了整个文件的基本属性,比如ELF文件版本,目标芯片类型,程序入口地址(Entry point address)

readelf -S  显示段表(Section Header Table)段表是elf文件除了文件头以外最重要的结构,描述了各个段的信息,比如各个段的段名,段的长度,在文件中的偏移、读写权限及段的其他属性。

编译器、链接器和装载器都是依靠段来定位和访问各个段的属性的,对比objdump -h也可以查看段表信息,但是不是完整的。

这里起始地址0x430等于上面的1072。

ELF相关的结构体定义在 “usr/include/elf.h”中,对应ndk的位置:./toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/linux/elf.h

关于段表的描述为一个结构体(Elf64_Shdr sizeof=64 (size of section header))数组,如上,对应长度为13的数组;

 最终的文件结构顺序以及长度如下:

序号

段内容

长度

偏移

对齐

ELF file Header

0x40

0

1

.text

0x55

0x40

1

2

.data

0x8

0x98

4

3

.bss

0

0xa0

4

.rodata

0x4

0xa0

1

5

.comment

0x36

0xa4

1

6

.note.GNU-stack

0

0xda

7

.eh_frame

0x58

0xe0

8

8

.symtab 符号表

0x180

0x138

8

9

.strtab

0x66

0x2b8

1

10

.rela.text

0x78

0x320

8

11

.rela.eh_frame

0x30

0x398

8

12

.shstrtab

0x61

0x3c8

1

段表

Section header

0x340 = 0x40*13

0x430

4?

文件长度:

0x770=1904

这与文件大小是可以对应上的:

readelf参考:

readelf 命令,Linux readelf 命令详解:用于显示elf格式文件的信息 - Linux 命令搜索引擎


http://chatgpt.dhexx.cn/article/myvFh2OM.shtml

相关文章

GCC详解-Binutils工具之readelf

1、介绍 readelf从ELF 格式的目标文件显示信息。 readelf和objdump提供的功能类似,但是它显示的信息更为具体,并且它不依赖BFD库(BFD库是一个GNU项目,它的目标就是希望通过一种统一的接口来处理不同的目标文件) 2、ELF格式的文件 ELF&…

readelf命令使用

0x1、概述 readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(*.so)或者静态库(*.a) 等包含ELF格式的文件。以下命令的使用是基于android编译出来的so文件上面去运行。 0x2、readelf常用命令 语法&#x…

readelf的使用

记录下有接触到的使用。 这个命令可以用来查询可执行文件依赖什么动态库,查看静态库中包含了什么.o文件。 1、查询可执行文件依赖什么动态库 2、静态库中包含了什么.o文件

linux readelf,Linux readelf命令使用

readelf用来显示ELF格式目标文件的信息.可通过参数选项来控制显示哪些特定信息。 (注意: readelf不支持显示archive文档, 也不支持64位的ELF文件)。 使用方法1: 查看共享库的依赖库(NEEDED)和搜索名(SONAME)。 readelf -d 例如: #readelf -d libuClibc-…

Linux命令:readelf

1 需求 关键参数: -h/--file-header Display the ELF file header-l/--program-headers/--segments Display the program headers-S/--section-headers/--sections Display the sections header-s/--syms/--symbols Display the symbol table--dyn-sys…

readelf命令使用说明

0x1、概述 readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(*.so)或者静态库(*.a) 等包含ELF格式的文件。以下命令的使用是基于android编译出来的so文件上面去运行。 0x2、readelf常用命令 语法&…

readelf指令使用

一、指令说明 readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(*.so)或者静态库(*.a) 等包含ELF格式的文件。以下命令的使用是基于android编译出来的so文件上面去运行。 readelf常用命令 语法&#xff…

Mysql开发实践:error while loading shared libraries: libaio解决方案

摘要:Mysql出现问题:error while loading shared libraries: libaio解决方案。 本文分享自华为云社区《Mysql出现问题:error while loading shared libraries: libaio解决方案》,作者: 小虚竹。 问题 初始化数据库时…

fio: engine libaio not loadable

用测试工具fio,并且安装方式是源码编译安装。 tar xzf fio-fio-3.18.tar.gz && cd fio-fio-3.18 ./configure make make install编译安装完,想要测试顺序读、顺序写等时候,出现下面的报错: fio: engine libaio not loade…

libaio在mysql中的作用,ubuntu安裝mysql遇到的坑----解決Mysql報錯缺少libaio.so.1

最近學習大數據,涉及到hive的部分需要安裝mysql,於是就在linux環境下嘗試安裝,對於我這個linux小白來說,中間遇到很多坑爹問題,在這里做一個記錄。 前面安裝的過程照着博客一步步來,照貓畫虎,沒…

libaio源码安装_MySQL5.7.17 编译安装及二进制安装详解

MySQL 的安装方式有很多,最常见的就是编译安装和二进制安装; 在这里我将两种安装方式都介绍一下,自由选择; 首先我们来看一下编译安装的步骤: 首先,到官方网站中下载源码包; Download MySQL Community Server 选择下载源码包: 有很多针对不同系统的源码包,我们选择通用…

linux 提示libaio.so.1,解决Mysql报错缺少libaio.so.1

解决Mysql报错缺少libaio.so.1 报错如上图,需要安装libaio.so.1 64位系统安装: wget http://mirror.centos.org/centos/6/os/x86_64/Packages/libaio-0.3.107-10.el6.x86_64.rpm rpm -ivh libaio-0.3.107-10.el6.x86_64.rpm 32位系统现在很少了,yum似乎默认安装32位的: yum…

libaio介绍和使用

libaio介绍 The Linux-native asynchronous I/O facility ("async I/O", or "aio") has a richer API and capability set than the simple POSIX async I/O facility. This library, libaio, provides the Linux-native API for async I/O. The POSIX as…

安装mysql-community-server报错缺少libaio依赖

一、遇到问题 安装mysql-community-common、mysql-community-libs、mysql-community-client都没有问题,但是安装myql-community-server就报错,缺少libaio依赖 二、解决问题 执行命令:yum -y install libaio 执行命令:rpm -ivh…

linux libaio介绍

Linux的I/O机制经历了一下几个阶段的演进: 1. 同步阻塞I/O: 用户进程进行I/O操作,一直阻塞到I/O操作完成为止。 2. 同步非阻塞I/O: 用户程序可以通过设置文件描述符的属性O_NONBLOCK,I/O操作可以立即返回,但是并不保证I/O操作成功…

Linux开发之libaio源码分析及应用

1. 简介 Linux的POSIX API由glibc提供,2000年年之前,glibc一直没有提供异步I/O的调用API。Red Hat公司基于Linux内核的符号表封装了一套异步I/O(简称aio)的接口,并提供了一些新的接口用来简化上下文配置,开成一个库,命…

HC-SR501人体红外感应电子模块

1)理解两种触发方式:可重复触发和不可重复触发 2)学会调节两个属性:延迟调节和灵敏度调节 (在不同触发方式下,大家要自己调自己的设备,不同延迟反应快速性不同,不同灵敏度感应的范围…

人体红外传感器简明教程

学习物联网,来HaaSEDU就对了 人体红外热释电运动传感器 一、产品简介 热释电红外运动传感器能检测运动的人或动物身上发出的红外线,输出开关信号,可以应用于各种需要检测运动人体的场合。传统的热释电红外传感器需要人体热释电红外探头、专…

基于STM32F0实现人体红外传感器

​​​​​​目的 了解人体红外传感器 HC-SR501 的驱动原理和STM32F030的中断机制,通过配置 STM32F030 芯片 GPIO 相关寄存器和外部触发中断实现人体红外传感器检测人体。 原理 中断是指当CPU执行程序时,由于发生了某种随机的事件(外部或内…

Arduino Uno 使用 人体红外传感器(HC_SR051)实现 人体感应灯

“登”,亮了., 每当我游走在图书馆书架之间就会有这样的一个情景。 这次实验使用的模块是人体红外传感器(HC_SR051),配上Arduino Uno 实现人体感应灯的实现。 先看看这模块(点击查看大图) 实验效…