ELF目標(biāo)文件與readelf

readelf elf文件格式分析

背景

目標(biāo)文件

首先需要介紹的概念是目標(biāo)文件(Object file)的概念。目標(biāo)文件是計(jì)算機(jī)科學(xué)中編譯器或匯編器處理源代碼后所生成的代碼(目標(biāo)代碼,Object code)的計(jì)算機(jī)文件,它常被稱作二進(jìn)制文件(binaries)。這個(gè)文件類型主要是區(qū)別于你看得懂的用人話寫的代碼文件(.c、.cpp etc.)、中間文件(.i)、匯編文件(.s)。常見的.exe、.dll、.so啥的都算目標(biāo)文件。

目標(biāo)文件有三種類型:

  • 可重定位的對(duì)象文件(Relocatable file)
    由匯編器匯編生成的 .o 文件(下面會(huì)詳細(xì)講到)
  • 可執(zhí)行的對(duì)象文件(Executable file)
    可執(zhí)行應(yīng)用程序
  • 可被共享的對(duì)象文件(Shared object file)
    動(dòng)態(tài)庫文件

編譯過程

編譯的過程如下圖所示


編譯過程

代碼文件經(jīng)過語言預(yù)處理器、編譯器、匯編器和鏈接器處理,最終生成可執(zhí)行目標(biāo)文件。

下面以一個(gè)簡(jiǎn)單的c語言文件為例:

sum.c源文件內(nèi)容如下:

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

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

通過運(yùn)行C預(yù)處理器(cpp)可以生成sum.i中間文件:

# 1 "sum.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 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;
}

通過運(yùn)行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)生成一個(gè)可重定位目標(biāo)文件(reloacatable object file)。

什么是ELF

系統(tǒng)里的目標(biāo)文件是按照特定的目標(biāo)文件格式來組織的,各個(gè)系統(tǒng)的目標(biāo)文件格式都不相同。

從貝爾實(shí)驗(yàn)室誕生的第一個(gè)Unix系統(tǒng)使用的是a.out格式(直到今天,可執(zhí)行文件仍然稱為a.out文件)。Windows使用可移植可執(zhí)行(PortableExecutable,PE)格式。Mac OS-X使用Mach-O格式。現(xiàn)代x86-64Linux和Unix系統(tǒng)使用可執(zhí)行可鏈接格式(Executable and Linkable Format,ELF)。

ELF格式的文件在Linux系統(tǒng)下有.axf、 .bin、 .elf、 .o、 .prx、 .puff、 .ko、 .mod和.so等等

readelf指令

前面介紹了這么多ELF的背景知識(shí),下面回來來說說readelf這個(gè)指令。這個(gè)指令正是用來查看目標(biāo)文件的內(nèi)容的。

ELF可重定位目標(biāo)文件的格式

典型格式

典型的ELF可重定位目標(biāo)文件的格式如下圖:


ELF可重定位目標(biāo)文件格式

其中:

  • .text 節(jié)里裝載了程序的可執(zhí)行機(jī)器碼
  • .rodata 節(jié)里裝載了只讀數(shù)據(jù)
  • .data 節(jié)里面裝載了被初始化的數(shù)據(jù),包括全局和靜態(tài)C變量
  • .bss 節(jié)里面裝載了未被初始化的全局和靜態(tài)C變量(在目標(biāo)文件中只是占位符,不占空間)
  • .symtab 或者 .dynsym 節(jié)里面裝載了符號(hào)信息
  • 以 .rel 打頭的 節(jié)里面裝載了重定位條目
  • .debug 一個(gè)調(diào)試符號(hào)表,只有使用了-g參數(shù)編譯時(shí)才會(huì)有,用于debug
  • .line 用于記錄C源程序的行號(hào)和.text節(jié)中機(jī)器指令之間的映射,也是只有使用了-g參數(shù)編譯時(shí)才會(huì)有
  • .strtab 或者 .dynstr 節(jié)里面裝載了字符串信息(以null結(jié)尾的字符串信息)

符號(hào)表部分解析

符號(hào)表每節(jié)定義如下:

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; 

具體解釋如下:


符號(hào)表思維導(dǎo)圖

舉個(gè)例子??

以上面的sum.c生成的sum.o為例,我們選取readelf-all參數(shù)輸出全部?jī)?nèi)容:

$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參數(shù)可以單獨(dú)得到)。

最后一部分是符號(hào)表部分(用-s參數(shù)可以單獨(dú)得到該部分),前面八個(gè)條目是鏈接器內(nèi)部使用的局部符號(hào),最后一行是全局符號(hào)sum定義的條目??梢酝ㄟ^最后一行看出,它是一個(gè)位于.text節(jié)中偏移量為0處的27字節(jié)函數(shù)。(Ndx部分表示在哪個(gè)節(jié)中,1表示.text節(jié),3表示.data節(jié),對(duì)應(yīng)上面輸出的Section Headers部分)

查看更多文章請(qǐng)?jiān)L問我的博客——左旋異構(gòu)
本文地址:左旋異構(gòu) - ELF目標(biāo)文件與readelf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容