前言

ELFlinux动态库,可执行文件的格式.具体介绍可参阅wiki Executable and Linkable Format。可以类比到windows下exe的格式。

首先推荐一个写的不错文档ELF格式

我们知道程序需要加载内存后才能运行。但是ELF文件加载到内存后布局会变化和原始ELF文件相比,加载器会将相同的节属性(比如只读)合并一个段。所以ELF也就有了两种视图,一种未加载前静态视图,另一种是加载后的动态视图。

我们首先了解静态视图ELF文件格式如下:

你可以把ELF内容大致分为四个部分:

(1) ELF头部

(2) 节

(3) 节表头

(4) 程序头

  1. ELF头部固定在ELF文件开始
  2. 需要留意程序头和节表头可以位于ELF任意位置,他们位置被ELF头部中的属性指定
  3. 节分有很多种格式需要根据节类别区分,比如重定义节 与代码节

本文根据以下代码作为示例

#include <stdio.h>static int mystaticVar = 3 ;
int myglobalvar=3;
//函数来自test.so
extern void testfun();
int main(){int *inp= 0x00;*inp=2;  testfun();static int myLocalVar1 = 3 ;static int myUnintLocallvar;printf("hello world %d \r\n",mystaticVar);return 0;
}
void hell(){
testfun();
}

目标文件 main.o
可执行文件main.out

ELF头部

我们以main.o 举例
我们用file查看文件类别

ELF 64-bit 告诉我们这个文件是一个64位系统下的ELF文件
LSBleast significant bit缩写表示第一个字节是多字节中最低有效位,简而言之就是小端模式
x86-64 是指该文件运行在那个处理器的ABI下
version 1(SYSV)是该ELF标准是UNIX_System_V具体参阅SYSV
not stripped表示该ELF存在符号表
relocatable 表示该文件是可重定位,因为main.o是目标文件而不是可执行文件,部分代码地址是不确定的

上面信息其实file程序读取该文件的elf头部得到。我们使用readelf -h文件头查看更详细的信息

数据结构如下所示

typedef struct
{unsigned char e_ident[EI_NIDENT];    /* Magic number and other info */Elf64_Half  e_type;          /* Object file type */Elf64_Half e_machine;       /* Architecture */Elf64_Word e_version;       /* Object file version */Elf64_Addr  e_entry;     /* Entry point virtual address */Elf64_Off   e_phoff;     /* Program header table file offset */Elf64_Off  e_shoff;     /* Section header table file offset */Elf64_Word e_flags;     /* Processor-specific flags */Elf64_Half e_ehsize;        /* ELF header size in bytes */Elf64_Half e_phentsize;     /* Program header table entry size */Elf64_Half  e_phnum;     /* Program header table entry count */Elf64_Half e_shentsize;     /* Section header table entry size */Elf64_Half  e_shnum;     /* Section header table entry count */Elf64_Half e_shstrndx;      /* Section header string table index */
} Elf64_Ehdr;

e_ident

一个16字节数组大小

完整参数参阅请参阅 ELF Header

elf.hEI_XXX表示上面下标位置

//elf.h
#define EI_NIDENT (16)
#define EI_MAG0     0/* File identification byte 0 index */
#define ELFMAG0     0x7f/* Magic number byte 0 */#define EI_MAG1       1/* File identification byte 1 index */
#define ELFMAG1     'E'     /* Magic number byte 1 */#define EI_MAG2      2/* File identification byte 2 index */
#define ELFMAG2     'L'     /* Magic number byte 2 */#define EI_MAG3      3/* File identification byte 3 index */
#define ELFMAG3     'F'     /* Magic number byte 3 *//* Conglomeration of the identification bytes, for easy testing as a word.  */
#define   ELFMAG        "\177ELF"
#define   SELFMAG       4#define EI_CLASS    4/* File class byte index */
#define ELFCLASSNONE    0/* Invalid class */
#define ELFCLASS32  1/* 32-bit objects */
#define ELFCLASS64  2/* 64-bit objects */
#define ELFCLASSNUM 3#define EI_DATA     5/* Data encoding byte index */
#define ELFDATANONE 0/* Invalid data encoding */
#define ELFDATA2LSB 1/* 2's complement, little endian */
#define ELFDATA2MSB 2/* 2's complement, big endian */
#define ELFDATANUM  3#define EI_VERSION  6/* File version byte index *//* Value must be EV_CURRENT */#define EI_OSABI 7/* OS ABI identification */
#define ELFOSABI_NONE       0/* UNIX System V ABI */
#define ELFOSABI_SYSV       0/* Alias.  */
#define ELFOSABI_HPUX       1/* HP-UX */
#define ELFOSABI_NETBSD     2/* NetBSD.  */
#define ELFOSABI_GNU        3/* Object uses GNU ELF extensions.  */
#define ELFOSABI_LINUX      ELFOSABI_GNU/* Compatibility alias.  */
#define ELFOSABI_SOLARIS    6/* Sun Solaris.  */
#define ELFOSABI_AIX        7/* IBM AIX.  */
#define ELFOSABI_IRIX       8/* SGI Irix.  */
#define ELFOSABI_FREEBSD    9/* FreeBSD.  */
#define ELFOSABI_TRU64      10/* Compaq TRU64 UNIX.  */
#define ELFOSABI_MODESTO    11/* Novell Modesto.  */
#define ELFOSABI_OPENBSD    12/* OpenBSD.  */
#define ELFOSABI_ARM_AEABI  64/* ARM EABI */
#define ELFOSABI_ARM        97/* ARM */
#define ELFOSABI_STANDALONE 255/* Standalone (embedded) application */#define EI_ABIVERSION   8/* ABI version */#define EI_PAD        9/* Byte index of padding bytes */
Name 下标范围 Purpose
ELF魔数 0-4 固定为0x7f+ELF
EI_CLASS 5 表示文件时32位还是64位 1是32 2是64
EI_DATA 6 指定大小端 1小端 2大端
EI_VERSION 7 ELF规范版本当前规定是1
EI_OSABI 8 ELF启用一些基于操作系统或者cpu特性一般为0
EI_ABIVERSION 9 一般为0 指定当前当ABI版本配合EI_OSABI使用
EI_PAD 10-F 预留
EI_NIDENT F e_ident[]数组大小

e_type

表示当前ELF文件类型,下面举例常见的类型

名字 数值 寓意
ET_NONE 0 非文件类型
ET_REL 1 可重定位文件
ET_EXEC 2 可执行文件
ET_DYN 3 共享库
ET_CORE 4 Core file

e_machine

制定当前ELF运行的CPU架构
下面举例常见的类型

名字 数值 寓意
EM_X86_64 62 AMD-x86-64

e_version

用于指定ELF版本一般都为1

e_entry

elf 代码运行的入口

e_flags

在e_machine指定的处理器下的一些特性

节头表相关字段

e_shoff
节头表在文件的偏移

e_shentsize
节头表中每个条目的大小

e_shnum
节头表中条目的数目

程序头相关字段

e_phoff
程序头在文件中的偏移

e_phentsize
指定程序头中每个条目的大小

e_phnum
指定程序头中每个条目的个数

e_shstrndx

每个节头都一个名称,这些名称都存储一个特殊节中。而e_shstrndx 指定这个特殊的节所在节头表的下标

我们先看看这个程序中所有节如下:

一共13个节,其中.shstrtab表示的存储字符串节 。
.shstrtabsection head string table

我们查看这个节内容如下所示:

大致结构如下:

节头

本例中我们依旧使用main.o我们可以到节头表信息如下:

节头表的第一项固定为空节不存储实际内容

每个节头数据结构如下:

typedef struct
{Elf64_Word  sh_name;     /* Section name (string tbl index) */Elf64_Word  sh_type;     /* Section type */Elf64_Xword    sh_flags;        /* Section flags */Elf64_Addr    sh_addr;     /* Section virtual addr at execution */Elf64_Off sh_offset;       /* Section file offset */Elf64_Xword sh_size;     /* Section size in bytes */Elf64_Word    sh_link;     /* Link to another section */Elf64_Word  sh_info;     /* Additional section information */Elf64_Xword  sh_addralign;        /* Section alignment */Elf64_Xword   sh_entsize;      /* Entry size if section holds table */
} Elf64_Shdr;

elf节头规则详细文档 https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.sheader.html

sh_name

节名在字符串节中下标,本例中字符串节名称为.shstrtab.我们举例其中一个节.text

我们看到.text节的sh_name为20h也就是十进制32.我们看下.shstrtab指向的字节数组的32位

sh_type

这个字段根据节的内容(content)和语义(semantics)对节进行分类。
分类类型有很多种,我们只举例其中比较常见的类型。

名称 数值 解释
SHT_PROGBITS 1 一般存放代码或者数据类型
SHT_STRTAB 3 存放字符串表类型
SHT_NOBITS 8 表示这个节不存储信息在文件中,比如未初始化的数据

.text.data一般就是SHT_PROGBITS (text存储代码 data存储数据)
.shstrtab一般是SHT_STRTAB
.bss一般是SHT_NOBITS (存储全局未初始化数据等)

sh_flags

字段标记是否可读可写可执行等,以及是否在内存中分配内存(SHF_ALLOC)
下图为枚举值表:

sh_addr

这个节被加载后对应VA地址

sh_offset

这个节在文件中的偏移

sh_size

节大小(不是指节头大小哦)

sh_link

一般用于关联节所在节头表的数组下标,一般为0
举例说明:
我们节中有一个专门用于重定位的节如.rela.text 就是用来重定位代码段部分代码的。
sh_link表示这个节所使用的的符号表节在节头表的下标
sh_info表示哪个节需要重定向。这个值指向在节头表中的索引。

如下图所示 :

sh_info

一般用于关联节所在节头表的数组下标,一般为0

sh_addralign

对其数值。如果为0或者1表示不对齐。
sh_addr必须为0或者对其sh_addralign取模

sh_entsize

ent是entry缩写。

部分节内部存储是固定数据结构条目数组,针对这类别节sh_entsize指代的是每个条目的字节大小。

举例说明:
符号表节名为.symtab,它存储若干固定结构的符号信息。如下图所示

符号表每个条目数据结构如下所示

typedef struct {Elf32_Word   st_name;Elf32_Addr   st_value;Elf32_Word  st_size;unsigned char  st_info;unsigned char  st_other;Elf32_Half  st_shndx;
} Elf32_Sym;//32位typedef struct {Elf64_Word   st_name;unsigned char  st_info;unsigned char  st_other;Elf64_Half  st_shndx;Elf64_Addr  st_value;Elf64_Xword st_size;
} Elf64_Sym;//64位

sh_entsize指的就是Elf64_Sym或者Elf32_Sym的大小

参考

ELF Header

ELF格式解读-(1) elf头部与节头相关推荐

  1. ELF格式解读-符号表

    前言 一个优先的symtab文章 我们常常调试错误说需要符号表,那么符号表是什么?符号表仅仅用来调试? 符号表本质就是一个映射表,举个例子:某行二进制汇编代码映射到源码第几行. 符号表的作用: 调试 ...

  2. Linux的ELF格式分析

    为什么80%的码农都做不了架构师?>>>    第一部分: ELF格式概述 ELF(Executable and Linkable Format)是一种对可执行文件.目标文件以及库文 ...

  3. linux elf格式文件详细分析

    ELF(Executable and Linkable Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西.以及都以什么样的格式去放这些东西. ...

  4. linux中elf文件的作用,Linux中ELF格式文件介绍

    一. ELF简介 ELF(Executable and Linkable Format)即可执行连接文件格式,是一种比较复杂的文件格式,但其应用广泛.与linux下的其他可执行文件(a.out,cof ...

  5. ELF格式文件详细分析

    ELF(Executable and Linkable Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西.以及都以什么样的格式去放这些东西. ...

  6. 一步步编写操作系统 47 elf格式文件分析实验

    在上一节中,我们讲述了elf格式的部分理论知识,为什么是部分呢?因为我们本着"够用"的原则,只把我们需要了解的部分说完啦.不过,我相信大部分同学仅仅凭上一节中的理论知识还是领悟不到 ...

  7. 初识ELF格式 ABI,EABI,OABI

    尽管每天都在调用linux的elf文件做各种事,但却很少去了解他,最近尝试在orangepi上编译个elf到android手机上运行,因为两个CPU都是ARMv8的.结果运行失败了.遂查找原因.结果挖 ...

  8. 【开发工具】【readelf】查看ELF格式文件工具(readelf)的使用

    目录 readelf概述 readelf命令使用说明 readelf概述 readelf是Linux下的分析ELF文件的命令,这个命令在分析ELF文件格式时非常有用.常见的文件如在Linux上的可执行 ...

  9. ELF 格式详解(一)

    ELF 全称 "Executable and Linkable Format",即可执行可链接文件格式,目前常见的Linux. Android可执行文件.共享库(.so).目标文件 ...

最新文章

  1. 解压zip_go|用Go写一个zip解压脚本
  2. oracle 表结构语句,oracle查询表结构语句
  3. Destroying the bus stations
  4. vue2.0框架认识
  5. windows下连接db2数据库
  6. C#中JSON和对象之间互相转换功能示例
  7. fusioncharts json java,FusionCharts使用教程:利用XML/JSON属性加载外部LOGO
  8. Apple Watch问与答
  9. 1054: 猴子吃桃
  10. 电子相框病毒,圣诞死灰复燃
  11. Mac系统辅助键盘怎么开启
  12. java reactive web,基于RxJava的函数式Reactive Web框架:datamill
  13. 贪心字典序最小问题poj3617
  14. Python 高性能编程
  15. 3dmax如何使阴天灯光设置更加自然
  16. 微信小程序中跳转另一个小程序(两种方式)
  17. 【瑞芯微RK3188 VS 全志A31】性能向多项目对比评测
  18. 【软件测试】你最常用的web测试-浏览器兼容性测试
  19. 一些个人感觉很不错的特效
  20. 求某年某月某日是星期几公式

热门文章

  1. linux tty设备号,linux tty设备
  2. 一招搞定某易云歌曲评论并生成漂亮词图,想爬什么歌就爬什么歌,练手推荐
  3. 没有学历,在IT界边缘苦苦挣扎的我们,该何去何从
  4. 图文详解:阿里宠儿【小兔】RabbitMQ的养成攻略
  5. Android 中的看门狗—Watchdog
  6. 3ds MAX 基本体建模,长方体、圆柱体和球体
  7. Unity制作RPG游戏——相机的设计与实现
  8. 极建立跨集团核电厂核事故应急救援
  9. ModelSim使用技巧总结(入门向)
  10. 无源停电报警器电路_报警器电路图讲解