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

一、简介

1、分类

  • 可重定位文件(Relocatable File) .o)包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。

  • 可执行文件(Executable File) .exe) 包含适合于执行的一个程序,此文件规定了exec() 如何创建一个程序的进程映像。

  • 共享目标文件(Shared Object File) .so) 包含可在两种上下文中链接的代码和数据。

    • 首先链接编辑器可以将它和其它可重定位文件和共享目标文件一起处理, 生成另外一个目标文件。
    • 其次动态链接器(Dynamic Linker)可能将它与某 个可执行文件以及其它共享目标一起组合,创建进程映像。

2、作用

ELF文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序),所以可以从不同的角度来看待elf格式的文件:

  • 如果用于编译和链接(可重定位文件),则编译器和链接器将把elf文件看作是节头表描述的节的集合,程序头表可选。

  • 如果用于加载执行(可执行文件),则加载器则将把elf文件看作是程序头表描述的段的集合,一个段可能包含多个节,节头表可选。

  • 如果是共享文件,则两者都含有。


二、格式分析

1、源文件

//============================================================================
// Name        : hello.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>
using namespace std;int main() {cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!return 0;
}
$g++ hello.cpp -o hello

2、ELF头部

$ readelf -h helloELF Header:Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class:                             ELF64Data:                              2's complement, little endianVersion:                           1 (current)OS/ABI:                            UNIX - System VABI Version:                       0Type:                              EXEC (Executable file)Machine:                           Advanced Micro Devices X86-64Version:                           0x1Entry point address:               0x400750Start of program headers:          64 (bytes into file)Start of section headers:          65016 (bytes into file)Flags:                             0x0Size of this header:               64 (bytes)Size of program headers:           56 (bytes)Number of program headers:         9Size of section headers:           64 (bytes)Number of section headers:         37Section header string table index: 34

文件的最开始几个字节给出如何解释文件的提示信息。这些信息独立于处理器,也独立于文件中的其余内容。ELF Header 部分可以用以下的数据结构表示:

/* ELF Header */
#define EI_NIDENT 16
typedef struct elfhdr {unsigned char    e_ident[EI_NIDENT]; /* ELF Identification */Elf32_Half    e_type;        /* object file type */Elf32_Half    e_machine;    /* machine */Elf32_Word    e_version;    /* object file version */Elf32_Addr    e_entry;      /* virtual entry point */Elf32_Off     e_phoff;      /* program header table offset */Elf32_Off     e_shoff;      /* section header table offset */Elf32_Word    e_flags;      /* processor-specific flags */Elf32_Half    e_ehsize;     /* ELF header size */Elf32_Half    e_phentsize;    /* program header entry size */Elf32_Half    e_phnum;      /* number of program header entries */Elf32_Half    e_shentsize;    /* section header entry size */Elf32_Half    e_shnum;      /* number of section header entries */Elf32_Half    e_shstrndx;    /* section header table's "section header string table" entry offset */
} Elf32_Ehdr;typedef struct {unsigned char    e_ident[EI_NIDENT];    /* Id bytes */Elf64_Quarter    e_type;            /* file type */Elf64_Quarter    e_machine;        /* machine type */Elf64_Half       e_version;        /* version number */Elf64_Addr       e_entry;         /* entry point */Elf64_Off        e_phoff;         /* Program hdr offset */Elf64_Off        e_shoff;         /* Section hdr offset */Elf64_Half       e_flags;         /* Processor flags */Elf64_Quarter    e_ehsize;        /* sizeof ehdr */Elf64_Quarter    e_phentsize;     /* Program header entry size */Elf64_Quarter    e_phnum;         /* Number of program headers */Elf64_Quarter    e_shentsize;     /* Section header entry size */Elf64_Quarter    e_shnum;         /* Number of section headers */Elf64_Quarter    e_shstrndx;      /* String table index */
} Elf64_Ehdr;

e_ident 数组给出了 ELF 的一些标识信息,这个数组中不同下标的含义如表所示:

这些索引访问包含以下数值的字节:

e_ident[EI_MAG0]~e_ident[EI_MAG3]e_ident[0]~e_ident[3]被称为魔数(Magic Number),其值一般为0x7f,'E','L','F'
e_ident[EI_CLASS](即e_ident[4])识别目标文件运行在目标机器的类别,取值可为三种值:ELFCLASSNONE(0)非法类别;ELFCLASS32(1)32位目标;ELFCLASS64(2)64位目标。
e_ident[EI_DATA](即e_ident[5]):给出处理器
特定数据的数据编码方式。即大端还是小端方式。取值可为3种:ELFDATANONE(0)非法数据编码;ELFDATA2LSB(1)高位在前;ELFDATA2MSB(2)低位在前。

ELF Header 中各个字段的说明如表:


3、程序头部(Program Header)

$ readelf -l helloElf file type is EXEC (Executable file)
Entry point 0x400750
There are 9 program headers, starting at offset 64Program Headers:Type           Offset             VirtAddr           PhysAddrFileSiz            MemSiz              Flags  AlignPHDR           0x0000000000000040 0x0000000000400040 0x00000000004000400x00000000000001f8 0x00000000000001f8  R E    8INTERP         0x0000000000000238 0x0000000000400238 0x00000000004002380x000000000000001c 0x000000000000001c  R      1[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]LOAD           0x0000000000000000 0x0000000000400000 0x00000000004000000x0000000000000ad4 0x0000000000000ad4  R E    200000LOAD           0x0000000000000df8 0x0000000000600df8 0x0000000000600df80x0000000000000268 0x0000000000000380  RW     200000DYNAMIC        0x0000000000000e18 0x0000000000600e18 0x0000000000600e180x00000000000001e0 0x00000000000001e0  RW     8NOTE           0x0000000000000254 0x0000000000400254 0x00000000004002540x0000000000000044 0x0000000000000044  R      4GNU_EH_FRAME   0x0000000000000958 0x0000000000400958 0x00000000004009580x0000000000000044 0x0000000000000044  R      4GNU_STACK      0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000  RW     10GNU_RELRO      0x0000000000000df8 0x0000000000600df8 0x0000000000600df80x0000000000000208 0x0000000000000208  R      1Section to Segment mapping:Segment Sections...00     01     .interp 02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 04     .dynamic 05     .note.ABI-tag .note.gnu.build-id 06     .eh_frame_hdr 07     08     .init_array .fini_array .jcr .dynamic .got

可执行文件或者共享目标文件的程序头部是一个结构数组,每个结构描述了一个段 或者系统准备程序执行所必需的其它信息。目标文件的“段”包含一个或者多个“节区”, 也就是“段内容(Segment Contents)”。程序头部仅对于可执行文件和共享目标文件 有意义。 可执行目标文件在 ELF 头部的 e_phentsizee_phnum 成员中给出其自身程序头部 的大小。程序头部的数据结构:

/* Program Header */
typedef struct {Elf32_Word    p_type;        /* segment type */Elf32_Off    p_offset;    /* segment offset */Elf32_Addr    p_vaddr;    /* virtual address of segment */Elf32_Addr    p_paddr;    /* physical address - ignored? */Elf32_Word    p_filesz;    /* number of bytes in file for seg. */Elf32_Word    p_memsz;    /* number of bytes in mem. for seg. */Elf32_Word    p_flags;    /* flags */Elf32_Word    p_align;    /* memory alignment */
} Elf32_Phdr;typedef struct {Elf64_Half    p_type;        /* entry type */Elf64_Half    p_flags;    /* flags */Elf64_Off    p_offset;    /* offset */Elf64_Addr    p_vaddr;    /* virtual address */Elf64_Addr    p_paddr;    /* physical address */Elf64_Xword    p_filesz;    /* file size */Elf64_Xword    p_memsz;    /* memory size */Elf64_Xword    p_align;    /* memory & file alignment */
} Elf64_Phdr;

其中各个字段说明:

  • p_type 此数组元素描述的段的类型,或者如何解释此数组元素的信息。具体如下图。
  • p_offset 此成员给出从文件头到该段第一个字节的偏移。
  • p_vaddr 此成员给出段的第一个字节将被放到内存中的虚拟地址。
  • p_paddr 此成员仅用于与物理地址相关的系统中。因为 System V 忽略所有应用程序的物理地址信息,此字段对与可执行文件和共享目标文件而言具体内容是指定的。
  • p_filesz 此成员给出段在文件映像中所占的字节数。可以为 0。
  • p_memsz 此成员给出段在内存映像中占用的字节数。可以为 0。
  • p_flags 此成员给出与段相关的标志。
  • p_align 可加载的进程段的 p_vaddr 和 p_offset 取值必须合适,相对于对页面大小的取模而言。此成员给出段在文件中和内存中如何 对齐。数值 0 和 1 表示不需要对齐。否则 p_align 应该是个正整数,并且是 2 的幂次数,p_vaddr 和 p_offset 对 p_align 取模后应该相等。

可执行 ELF 目标文件中的段类型:

4、节区(Sections)

$ readelf -S hello
There are 37 section headers, starting at offset 0xfdf8:Section Headers:[Nr] Name              Type             Address           OffsetSize              EntSize          Flags  Link  Info  Align[ 0]                   NULL             0000000000000000  000000000000000000000000  0000000000000000           0     0     0[ 1] .interp           PROGBITS         0000000000400238  00000238000000000000001c  0000000000000000   A       0     0     1[ 2] .note.ABI-tag     NOTE             0000000000400254  000002540000000000000020  0000000000000000   A       0     0     4[ 3] .note.gnu.build-i NOTE             0000000000400274  000002740000000000000024  0000000000000000   A       0     0     4[ 4] .gnu.hash         GNU_HASH         0000000000400298  000002980000000000000030  0000000000000000   A       5     0     8[ 5] .dynsym           DYNSYM           00000000004002c8  000002c80000000000000138  0000000000000018   A       6     1     8[ 6] .dynstr           STRTAB           0000000000400400  000004000000000000000168  0000000000000000   A       0     0     1[ 7] .gnu.version      VERSYM           0000000000400568  00000568000000000000001a  0000000000000002   A       5     0     2[ 8] .gnu.version_r    VERNEED          0000000000400588  000005880000000000000040  0000000000000000   A       6     2     8[ 9] .rela.dyn         RELA             00000000004005c8  000005c80000000000000030  0000000000000018   A       5     0     8[10] .rela.plt         RELA             00000000004005f8  000005f800000000000000a8  0000000000000018  AI       5    24     8[11] .init             PROGBITS         00000000004006a0  000006a0000000000000001a  0000000000000000  AX       0     0     4[12] .plt              PROGBITS         00000000004006c0  000006c00000000000000080  0000000000000010  AX       0     0     16[13] .plt.got          PROGBITS         0000000000400740  000007400000000000000008  0000000000000000  AX       0     0     8[14] .text             PROGBITS         0000000000400750  0000075000000000000001e2  0000000000000000  AX       0     0     16[15] .fini             PROGBITS         0000000000400934  000009340000000000000009  0000000000000000  AX       0     0     4[16] .rodata           PROGBITS         0000000000400940  000009400000000000000016  0000000000000000   A       0     0     4[17] .eh_frame_hdr     PROGBITS         0000000000400958  000009580000000000000044  0000000000000000   A       0     0     4[18] .eh_frame         PROGBITS         00000000004009a0  000009a00000000000000134  0000000000000000   A       0     0     8[19] .init_array       INIT_ARRAY       0000000000600df8  00000df80000000000000010  0000000000000000  WA       0     0     8[20] .fini_array       FINI_ARRAY       0000000000600e08  00000e080000000000000008  0000000000000000  WA       0     0     8[21] .jcr              PROGBITS         0000000000600e10  00000e100000000000000008  0000000000000000  WA       0     0     8[22] .dynamic          DYNAMIC          0000000000600e18  00000e1800000000000001e0  0000000000000010  WA       6     0     8[23] .got              PROGBITS         0000000000600ff8  00000ff80000000000000008  0000000000000008  WA       0     0     8[24] .got.plt          PROGBITS         0000000000601000  000010000000000000000050  0000000000000008  WA       0     0     8[25] .data             PROGBITS         0000000000601050  000010500000000000000010  0000000000000000  WA       0     0     8[26] .bss              NOBITS           0000000000601060  000010600000000000000118  0000000000000000  WA       0     0     32[27] .comment          PROGBITS         0000000000000000  000010600000000000000034  0000000000000001  MS       0     0     1[28] .debug_aranges    PROGBITS         0000000000000000  000010940000000000000030  0000000000000000           0     0     1[29] .debug_info       PROGBITS         0000000000000000  000010c400000000000015ca  0000000000000000           0     0     1[30] .debug_abbrev     PROGBITS         0000000000000000  0000268e00000000000003bf  0000000000000000           0     0     1[31] .debug_line       PROGBITS         0000000000000000  00002a4d000000000000075e  0000000000000000           0     0     1[32] .debug_str        PROGBITS         0000000000000000  000031ab0000000000009aad  0000000000000001  MS       0     0     1[33] .debug_macro      PROGBITS         0000000000000000  0000cc580000000000002512  0000000000000000           0     0     1[34] .shstrtab         STRTAB           0000000000000000  0000fc980000000000000159  0000000000000000           0     0     1[35] .symtab           SYMTAB           0000000000000000  0000f17000000000000007b0  0000000000000018          36    56     8[36] .strtab           STRTAB           0000000000000000  0000f9200000000000000378  0000000000000000           0     0     1
Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), l (large)I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)O (extra OS processing required) o (OS specific), p (processor specific)

节区中包含目标文件中的所有信息,除了:ELF 头部、程序头部表格、节区头部表格。节区满足以下条件:

  • 目标文件中的每个节区都有对应的节区头部描述它,反过来,有节区头部不意 味着有节区。
  • 每个节区占用文件中一个连续字节区域(这个区域可能长度为 0)。
  • 文件中的节区不能重叠,不允许一个字节存在于两个节区中的情况发生。
  • 目标文件中可能包含非活动空间(INACTIVE SPACE)。这些区域不属于任何头部和节区,其内容指定。

节区头部表格

ELF 头部中,e_shoff 成员给出从文件头到节区头部表格的偏移字节数;e_shnum 给出表格中条目数目;e_shentsize 给出每个项目的字节数。从这些信息中可以确切地定 位节区的具体位置、长度。

每个节区头部数据结构描述:

/* Section Header */
typedef struct {Elf32_Word    sh_name;    /* name - index into section headerstring table section */Elf32_Word    sh_type;    /* type */Elf32_Word    sh_flags;    /* flags */Elf32_Addr    sh_addr;    /* address */Elf32_Off     sh_offset;    /* file offset */Elf32_Word    sh_size;    /* section size */Elf32_Word    sh_link;    /* section header table index link */Elf32_Word    sh_info;    /* extra information */Elf32_Word    sh_addralign;    /* address alignment */Elf32_Word    sh_entsize;    /* section entry size */
} Elf32_Shdr;typedef struct {Elf64_Half    sh_name;    /* section name */Elf64_Half    sh_type;    /* section type */Elf64_Xword   sh_flags;    /* section flags */Elf64_Addr    sh_addr;    /* virtual address */Elf64_Off     sh_offset;    /* file offset */Elf64_Xword   sh_size;    /* section size */Elf64_Half    sh_link;    /* link to another */Elf64_Half    sh_info;    /* misc info */Elf64_Xword   sh_addralign;    /* memory alignment */Elf64_Xword   sh_entsize;    /* table entry size */
} Elf64_Shdr;

各个字段的解释如下:

索引为零(SHN_UNDEF)的节区头部是存在的,尽管此索引标记的是未定义的节区应用。这个节区固定为:

sh_type 字段 节区类型定义:

sh_flags 字段定义了一个节区中包含的内容是否可以修改、是否可以执行等信息。 如果一个标志位被设置,则该位取值为 1。 定义的各位都设置为 0。

其中已经定义了的各位含义如下:

  • SHF_WRITE: 节区包含进程执行过程中将可写的数据。
  • SHF_ALLOC: 此节区在进程执行过程中占用内存。某些控制节区- 并不出现于目标文件的内存映像中,对于那些节区,此位应设置为 0。
  • SHF_EXECINSTR: 节区包含可执行的机器指令。
  • SHF_MASKPROC: 所有包含于此掩码中的四位都用于处理器专用的语义。

根据节区类型的不同,sh_link 和 sh_info 的具体含义也有所不同:

特殊节区
系统使用的节区,以及它们 的类型和属性:

在分析这些节区的时候,需要注意如下事项:

  • 以“.”开头的节区名称是系统保留的。应用程序可以使用没有前缀的节区名称,以避 免与系统节区冲突。
  • 目标文件格式允许人们定义不在上述列表中的节区。
  • 目标文件中也可以包含多个名字相同的节区。
  • 保留给处理器体系结构的节区名称一般构成为:处理器体系结构名称简写 + 节区名称。
  • 处理器名称应该与 e_machine 中使用的名称相同。例如 .FOO.psect 街区是由FOO 体系结构定义的 psect 节区。

5、字符串表(String Table)

字符串表节区包含以 NULL(ASCII 码 0)结尾的字符序列,通常称为字符串。ELF 目标文件通常使用字符串来表示符号和节区名称。对字符串的引用通常以字符串在字符 串表中的下标给出。

一般,第一个字节(索引为 0)定义为一个空字符串。类似的,字符串表的最后一 个字节也定义为 NULL,以确保所有的字符串都以 NULL 结尾。索引为 0 的字符串在 不同的上下文中可以表示无名或者名字为 NULL 的字符串。

允许存在空的字符串表节区,其节区头部的 sh_size 成员应该为 0。对空的字符串 表而言,非 0 的索引值是非法的。

在使用、分析字符串表时,要注意以下几点:

  • 字符串表索引可以引用节区中任意字节。
  • 字符串可以出现多次
  • 可以存在对子字符串的引用
  • 同一个字符串可以被引用多次。
  • 字符串表中也可以存在未引用的字符串。

6、符号表(Symbol Table)

目标文件的符号表中包含用来定位、重定位程序中符号定义和引用的信息。符号表 索引是对此数组的索引。索引 0 表示表中的第一表项,同时也作为 定义符号的索引。

/* Symbol Table Entry */
typedef struct elf32_sym {Elf32_Word    st_name;    /* name - index into string table */Elf32_Addr    st_value;    /* symbol value */Elf32_Word    st_size;    /* symbol size */unsigned char    st_info;    /* type and binding */unsigned char    st_other;    /* 0 - no defined meaning */Elf32_Half    st_shndx;    /* section header index */
} Elf32_Sym;typedef struct {Elf64_Half    st_name;    /* Symbol name index in str table */Elf_Byte    st_info;    /* type / binding attrs */Elf_Byte    st_other;    /* unused */Elf64_Quarter    st_shndx;    /* section index of symbol */Elf64_Xword    st_value;    /* value of symbol */Elf64_Xword    st_size;    /* size of symbol */
} Elf64_Sym;

三、参考

http://www.cnblogs.com/xmphoenix/archive/2011/10/23/2221879.html
http://bdxnote.blog.163.com/blog/static/8444235201532911597959/
http://blog.csdn.net/wh8_2011/article/details/50812434
https://segmentfault.com/a/1190000007103522?utm_source=tuicool&utm_medium=referral

ELF格式文件详细分析相关推荐

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

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

  2. hadoop之slaves文件详细分析

    hadoop之saves文件详细分析(一) 注:所有操作基于hadopp-2.7.5,本篇文章主要涉及一些对于slaves文件之于hadoop平台的思考 首先大家都知道,要想配置一个完全分布式平台,首 ...

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

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

  4. FLV文件(H264 + AAC)格式超详细分析

    最近自己动手将H264视频流和AAC音频流合成flv文件,但是没有采用开源的ffmpeg的api来处理音视频流.方法就是模仿ffmpeg中libavformat/flvenc.c 文件写代码来完成音视 ...

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

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

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

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

  7. s3c2440启动文件详细分析

    启动文件就是引导ARM启动,并进入我们熟悉的C语言程序.它主要完成了ARM最基本的硬件初始化工作.虽然启动文件的内容大同小异(就是设置系统时钟.内存.中断向量表.栈等内容),而且只要有一个现成的启动文 ...

  8. Hex、bin、axf、elf格式文件小结

    一.HEX Hex文件,一般是指Intel标准的十六进制文件.Intelhex 文件常用来保存单片机或其他处理器的目标程序代码.它保存物理程序存储区中的目标代码映象.一般编程器均支持生成此种格式文件. ...

  9. 对于TGA格式文件的分析

    一.TGA格式文件概述 TGA格式图片文件(Tagged Graphics)是由美国Truevision公司为其显示卡开发的一种图像文件格式,文件后缀为".tga",已被国际上的图 ...

最新文章

  1. 用C++实现约瑟夫环的问题
  2. mysql 本地备份_MYSQL数据库自动本地/异地双备份/MYSQL增量备份
  3. 图像处理:像素间的基本关系
  4. 配置msf连接postgresql数据库
  5. java实现rabbitMQ延时队列详解以及spring-rabbit整合教程
  6. 优酷土豆闪婚 婚后孩子是问题
  7. java扫雷具有win7_window自带扫雷|扫雷下载|经典扫雷_win7扫雷下载_多特软件站
  8. 咖啡加盟10年经验分享:咖啡店12种危机处理方式,提升回头客
  9. 使用linux内核仿真ZNS(zoned namespace SSD)
  10. java integer转成负数_Java 十进制和十六制之间的转化(负数的处理)
  11. seed lab 2020 packet sniffing and spoofing lab
  12. 尝试使用sklearn自动进行多模型预测并计算权重
  13. 计算机界五位巾帼英雄
  14. 定制化chromium的修改方法
  15. 2018麦考林杂志计算机科学,2020年麦考林杂志排名全解析
  16. 绩效考核-项目经理绩效考核指标
  17. 严重: Null component Catalina:type=JspMonitor,name=jsp,WebModule=//localhost
  18. 先锋录音系统服务器,先锋音讯IP电话云录音系统——全球首创
  19. spring mvc中实现csrf安全防御简记
  20. Java获取下周、本周、上月、本月第一天最后一天

热门文章

  1. 使用ffmpeg实现视频连接
  2. MyEclipse安装tfs插件
  3. 计算机系大二学期计划范文,大二学期学习计划范文6篇_大二学生学习计划(2)
  4. 达人评测 苹果macbookpro2021款怎么样
  5. 《Data Mining》第2章翻译 数据预处理
  6. 反击呼之欲出:有效抵御金融危机的个股
  7. python爬取北师大珠海分校全校课程表
  8. Excel中如何用身份证号提取计算年龄?
  9. 使用CxImage进行图形和格式转换(CBitmap to jpg or png or gif or bmp)
  10. python 输出2000到2050闰年