ELF目标文件与readelf

readelf elf文件格式分析

背景

目标文件

首先需要介绍的概念是目标文件(Object file)的概念。目标文件是计算机科学中编译器或汇编器处理源代码后所生成的代码(目标代码,Object code)的计算机文件,它常被称作二进制文件(binaries)。这个文件类型主要是区别于你看得懂的用人话写的代码文件(.c、.cpp etc.)、中间文件(.i)、汇编文件(.s)。常见的.exe、.dll、.so啥的都算目标文件。

目标文件有三种类型:

  • 可重定位的对象文件(Relocatable file)
    由汇编器汇编生成的 .o 文件(下面会详细讲到)
  • 可执行的对象文件(Executable file)
    可执行应用程序
  • 可被共享的对象文件(Shared object file)
    动态库文件

编译过程

编译的过程如下图所示


ELF目标文件与readelf_第1张图片
编译过程

代码文件经过语言预处理器、编译器、汇编器和链接器处理,最终生成可执行目标文件。

下面以一个简单的c语言文件为例:

sum.c源文件内容如下:

int sum(int *a, int n)
{
  int i, s = 0;

  for (i = 0; i < n; ++i) {
    s += a[i];
  }
  return s;
}

通过运行C预处理器(cpp)可以生成sum.i中间文件:

# 1 "sum.c"
# 1 ""
# 1 ""
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "" 2
# 1 "sum.c"
int sum(int *a, int n)
{
  int i, s = 0;

  for (i = 0; i < n; ++i) {
    s += a[i];
  }
  return s;
}

通过运行C编译器(cc1),将中间文件生成为sum.s汇编文件:

  .file›"sum.i"
  .text
  .globl  sum
  .type›sum, @function
sum:
.LFB0:
  .cfi_startproc
  movl  $0, %eax
  movl  $0, %edx
  jmp›.L2
.L3:
  movslq  %edx, %rcx
  addl  (%rdi,%rcx,4), %eax
  addl  $1, %edx
.L2:
  cmpl  %esi, %edx
  jl  .L3
  rep ret
  .cfi_endproc
.LFE0:
  .size›sum, .-sum
  .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)"
  .section  .note.GNU-stack,"",@progbits

最终生成通过汇编器(as)生成一个可重定位目标文件(reloacatable object file)。

什么是ELF

系统里的目标文件是按照特定的目标文件格式来组织的,各个系统的目标文件格式都不相同。

从贝尔实验室诞生的第一个Unix系统使用的是a.out格式(直到今天,可执行文件仍然称为a.out文件)。Windows使用可移植可执行(PortableExecutable,PE)格式。Mac OS-X使用Mach-O格式。现代x86-64Linux和Unix系统使用可执行可链接格式(Executable and Linkable Format,ELF)。

ELF格式的文件在Linux系统下有.axf、 .bin、 .elf、 .o、 .prx、 .puff、 .ko、 .mod和.so等等

readelf指令

前面介绍了这么多ELF的背景知识,下面回来来说说readelf这个指令。这个指令正是用来查看目标文件的内容的。

ELF可重定位目标文件的格式

典型格式

典型的ELF可重定位目标文件的格式如下图:


ELF目标文件与readelf_第2张图片
ELF可重定位目标文件格式

其中:

  • .text 节里装载了程序的可执行机器码
  • .rodata 节里装载了只读数据
  • .data 节里面装载了被初始化的数据,包括全局和静态C变量
  • .bss 节里面装载了未被初始化的全局和静态C变量(在目标文件中只是占位符,不占空间)
  • .symtab 或者 .dynsym 节里面装载了符号信息
  • 以 .rel 打头的 节里面装载了重定位条目
  • .debug 一个调试符号表,只有使用了-g参数编译时才会有,用于debug
  • .line 用于记录C源程序的行号和.text节中机器指令之间的映射,也是只有使用了-g参数编译时才会有
  • .strtab 或者 .dynstr 节里面装载了字符串信息(以null结尾的字符串信息)

符号表部分解析

符号表每节定义如下:

typedef struct { 
    int   name;      /* String table offset */ 
    char  type:4,    /* Function or data (4 bits) */ 
      binding:4; /* Local or global (4 bits) */ 
    char  reserved;  /* Unused */  
    short section;   /* Section header index */
    long  value;     /* Section offset or absolute address */ 
    long  size;      /* Object size in bytes */ 
} Elf64_Symbol; 

具体解释如下:


ELF目标文件与readelf_第3张图片
符号表思维导图

举个例子

以上面的sum.c生成的sum.o为例,我们选取readelf-all参数输出全部内容:

$readelf -all sum.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          536 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         11
  Section header string table index: 10

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       000000000000001b  0000000000000000  AX       0     0     1
  [ 2] .data             PROGBITS         0000000000000000  0000005b
       0000000000000000  0000000000000000  WA       0     0     1
  [ 3] .bss              NOBITS           0000000000000000  0000005b
       0000000000000000  0000000000000000  WA       0     0     1
  1 int sum(int *a, int n)
  2 {
  [ 4] .comment          PROGBITS         0000000000000000  0000005b
       000000000000002e  0000000000000001  MS       0     0     1
  [ 5] .note.GNU-stack   PROGBITS         0000000000000000  00000089
       0000000000000000  0000000000000000           0     0     1
  [ 6] .eh_frame         PROGBITS         0000000000000000  00000090
       0000000000000030  0000000000000000   A       0     0     8
  [ 7] .rela.eh_frame    RELA             0000000000000000  000001a8
       0000000000000018  0000000000000018   I       8     6     8
  [ 8] .symtab           SYMTAB           0000000000000000  000000c0
       00000000000000d8  0000000000000018           9     8     8
  [ 9] .strtab           STRTAB           0000000000000000  00000198
       000000000000000b  0000000000000000           0     0     1
  [10] .shstrtab         STRTAB           0000000000000000  000001c0
       0000000000000054  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

Relocation section '.rela.eh_frame' at offset 0x1a8 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.symtab' contains 9 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS sum.i
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     8: 0000000000000000    27 FUNC    GLOBAL DEFAULT    1 sum

No version information found in this file.

其中第一部分是ELF头(ELF header)中的描述信息。(用-h参数可以单独得到)。

最后一部分是符号表部分(用-s参数可以单独得到该部分),前面八个条目是链接器内部使用的局部符号,最后一行是全局符号sum定义的条目。可以通过最后一行看出,它是一个位于.text节中偏移量为0处的27字节函数。(Ndx部分表示在哪个节中,1表示.text节,3表示.data节,对应上面输出的Section Headers部分)

查看更多文章请访问我的博客——左旋异构
本文地址:左旋异构 - ELF目标文件与readelf

你可能感兴趣的:(ELF目标文件与readelf)