readelf命令和ELF檔案詳解

readyao發表於2017-10-12

ELF(Executable and Linking Format)是一個定義了目標檔案內部資訊如何組成和組織的檔案格式。核心會根據這些資訊載入可執行檔案,核心根據這些資訊可以知道從檔案哪裡獲取程式碼,從哪裡獲取初始化資料,在哪裡應該載入共享庫,等資訊。
ELF檔案有下面三種型別:
1.目標檔案

$ gcc -c test.c
得到的test.o就是目標檔案,目標檔案通過連結可生成可執行檔案。
靜態庫其實也算目標檔案,靜態庫是通過ar命令將目標打包為.a檔案。
如:ar crv libtest.a test.o

2.可執行檔案
$gcc -o test test.c
得到的test檔案就是可執行的二進位制檔案。

3.共享庫
$ gcc test.c -fPIC -shared -o libtest.so
得到的檔案listtest.so就是共享庫。

可以通過readelf來區分上面三種型別的ELF檔案,每種型別檔案的頭部資訊是不一樣的。
$readelf -h test.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:          456 (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:         13
  Section header string table index: 10

$readelf -h test
可執行檔案

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:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400420
  Start of program headers:          64 (bytes into file)
  Start of section headers:          2696 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         8
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 27

$readelf -h libtest.so
共享庫

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:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x570
  Start of program headers:          64 (bytes into file)
  Start of section headers:          2768 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         6
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 26

下面是test.c檔案內容:

#include<stdio.h>

int global_data = 4;
int global_data_2;
int main(int argc, char **argv)
{ 
    int local_data = 3; 

    printf("Hello World\n"); 
    printf("global_data = %d\n", global_data); 
    printf("global_data_2 = %d\n", global_data_2); 
    printf("local_data = %d\n", local_data); 

    return (0);
}

$gcc -o test test.c
生成可執行檔案test,然後使用readelf對其進行分析。

$readelf -h test
下面是輸出結果:

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:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400420
  Start of program headers:          64 (bytes into file)
  Start of section headers:          2696 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         8
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 27

上面的資訊可以告訴我們什麼資訊?
1.根據Class、Type和Machine,可以知道該檔案在X86-64位機器上生成的64位可執行檔案。
2.根據Entry point address,可以知道當該程式啟動時從虛擬地址0x400420處開始執行。這個地址並不是main函式的地址,而是_start函式的地址,_start由連結器建立,_start是為了初始化程式。通過這個命令可以看到_start函式,objdump -d -j .text test
3.根據Number of program headers,可以知道該程式有8個段。
4.根據Number of section headers,可以知道該程式有30個區。
區中儲存的資訊是用來連結使用的,主要包括:程式程式碼、程式資料(變數)、重定向資訊等。比如:Code section儲存的是程式碼,data section儲存的是初始化或未初始化的資料,等等。

Linux核心無法以區的概念來識別可執行檔案。核心使用包括連續頁的VMA(virtual memory area)來識別程式。在每個VMA中可能對映了一個或多個區。每個VMA代表一個ELF檔案的段。
那麼,核心如何知道哪個區屬於某個VMA(段)?對映關係儲存在Program Header Table(PHT)中。

下面檢視區的內容:
$readelf -S test

There are 30 section headers, starting at offset 0xa88:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400200  00000200
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             000000000040021c  0000021c
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             000000000040023c  0000023c
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400260  00000260
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           0000000000400280  00000280
       0000000000000078  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           00000000004002f8  000002f8
       0000000000000044  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           000000000040033c  0000033c
       000000000000000a  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400348  00000348
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400368  00000368
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400380  00000380
       0000000000000048  0000000000000018   A       5    12     8
  [11] .init             PROGBITS         00000000004003c8  000003c8
       0000000000000018  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000004003e0  000003e0
       0000000000000040  0000000000000010  AX       0     0     4
  [13] .text             PROGBITS         0000000000400420  00000420
       0000000000000238  0000000000000000  AX       0     0     16
  [14] .fini             PROGBITS         0000000000400658  00000658
       000000000000000e  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         0000000000400668  00000668
       0000000000000053  0000000000000000   A       0     0     8
  [16] .eh_frame_hdr     PROGBITS         00000000004006bc  000006bc
       0000000000000024  0000000000000000   A       0     0     4
  [17] .eh_frame         PROGBITS         00000000004006e0  000006e0
       000000000000007c  0000000000000000   A       0     0     8
  [18] .ctors            PROGBITS         0000000000600760  00000760
       0000000000000010  0000000000000000  WA       0     0     8
  [19] .dtors            PROGBITS         0000000000600770  00000770
       0000000000000010  0000000000000000  WA       0     0     8
  [20] .jcr              PROGBITS         0000000000600780  00000780
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000600788  00000788
       0000000000000190  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000600918  00000918
       0000000000000008  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000600920  00000920
       0000000000000030  0000000000000008  WA       0     0     8
  [24] .data             PROGBITS         0000000000600950  00000950
       0000000000000008  0000000000000000  WA       0     0     4
  [25] .bss              NOBITS           0000000000600958  00000958
       0000000000000018  0000000000000000  WA       0     0     8
  [26] .comment          PROGBITS         0000000000000000  00000958
       000000000000002c  0000000000000001  MS       0     0     1
  [27] .shstrtab         STRTAB           0000000000000000  00000984
       00000000000000fe  0000000000000000           0     0     1
  [28] .symtab           SYMTAB           0000000000000000  00001208
       0000000000000648  0000000000000018          29    46     8
  [29] .strtab           STRTAB           0000000000000000  00001850
       000000000000021e  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

.text區儲存的是程式的程式碼(二進位制指令),該區的標誌為X表示可執行。

下面使用objdump反彙編檢視.text的內容:
$objdump -d -j .text test
-d選項告訴objdump反彙編機器碼,-j選項告訴objdump只關心.text區。

test:     file format elf64-x86-64


Disassembly of section .text:

0000000000400420 <_start>:
  400420:       31 ed                   xor    %ebp,%ebp
  400422:       49 89 d1                mov    %rdx,%r9
  400425:       5e                      pop    %rsi
  400426:       48 89 e2                mov    %rsp,%rdx
  400429:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  40042d:       50                      push   %rax
  40042e:       54                      push   %rsp
  40042f:       49 c7 c0 80 05 40 00    mov    $0x400580,%r8
  400436:       48 c7 c1 90 05 40 00    mov    $0x400590,%rcx
  40043d:       48 c7 c7 04 05 40 00    mov    $0x400504,%rdi
  400444:       e8 c7 ff ff ff          callq  400410 <__libc_start_main@plt>
  400449:       f4                      hlt    
  40044a:       90                      nop
  40044b:       90                      nop

000000000040044c <call_gmon_start>:
  40044c:       48 83 ec 08             sub    $0x8,%rsp
  400450:       48 8b 05 c1 04 20 00    mov    0x2004c1(%rip),%rax        # 600918 <_DYNAMIC+0x190>
  400457:       48 85 c0                test   %rax,%rax
  40045a:       74 02                   je     40045e <call_gmon_start+0x12>
  40045c:       ff d0                   callq  *%rax
  40045e:       48 83 c4 08             add    $0x8,%rsp
  400462:       c3                      retq   
  400463:       90                      nop
  400464:       90                      nop
  400465:       90                      nop
  400466:       90                      nop
  400467:       90                      nop
  400468:       90                      nop
  400469:       90                      nop
  40046a:       90                      nop
  40046b:       90                      nop
  40046c:       90                      nop
  40046d:       90                      nop
  40046e:       90                      nop
  40046f:       90                      nop

0000000000400470 <__do_global_dtors_aux>:
  400470:       55                      push   %rbp
  400471:       48 89 e5                mov    %rsp,%rbp
  400474:       53                      push   %rbx
  400475:       48 83 ec 08             sub    $0x8,%rsp
  400479:       80 3d d8 04 20 00 00    cmpb   $0x0,0x2004d8(%rip)        # 600958 <__bss_start>
  400480:       75 4b                   jne    4004cd <__do_global_dtors_aux+0x5d>
  400482:       bb 78 07 60 00          mov    $0x600778,%ebx
  400487:       48 8b 05 d2 04 20 00    mov    0x2004d2(%rip),%rax        # 600960 <dtor_idx.6349>
  40048e:       48 81 eb 70 07 60 00    sub    $0x600770,%rbx
  400495:       48 c1 fb 03             sar    $0x3,%rbx
  400499:       48 83 eb 01             sub    $0x1,%rbx
  40049d:       48 39 d8                cmp    %rbx,%rax
  4004a0:       73 24                   jae    4004c6 <__do_global_dtors_aux+0x56>
  4004a2:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
  4004a8:       48 83 c0 01             add    $0x1,%rax
  4004ac:       48 89 05 ad 04 20 00    mov    %rax,0x2004ad(%rip)        # 600960 <dtor_idx.6349>
  4004b3:       ff 14 c5 70 07 60 00    callq  *0x600770(,%rax,8)
  4004ba:       48 8b 05 9f 04 20 00    mov    0x20049f(%rip),%rax        # 600960 <dtor_idx.6349>
  4004c1:       48 39 d8                cmp    %rbx,%rax
  4004c4:       72 e2                   jb     4004a8 <__do_global_dtors_aux+0x38>
  4004c6:       c6 05 8b 04 20 00 01    movb   $0x1,0x20048b(%rip)        # 600958 <__bss_start>
  4004cd:       48 83 c4 08             add    $0x8,%rsp
  4004d1:       5b                      pop    %rbx
  4004d2:       c9                      leaveq 
  4004d3:       c3                      retq   
  4004d4:       66 66 66 2e 0f 1f 84    data32 data32 nopw %cs:0x0(%rax,%rax,1)
  4004db:       00 00 00 00 00 

00000000004004e0 <frame_dummy>:
  4004e0:       48 83 3d 98 02 20 00    cmpq   $0x0,0x200298(%rip)        # 600780 <__JCR_END__>
  4004e7:       00 
  4004e8:       55                      push   %rbp
  4004e9:       48 89 e5                mov    %rsp,%rbp
  4004ec:       74 12                   je     400500 <frame_dummy+0x20>
  4004ee:       b8 00 00 00 00          mov    $0x0,%eax
  4004f3:       48 85 c0                test   %rax,%rax
  4004f6:       74 08                   je     400500 <frame_dummy+0x20>
  4004f8:       bf 80 07 60 00          mov    $0x600780,%edi
  4004fd:       c9                      leaveq 
  4004fe:       ff e0                   jmpq   *%rax
  400500:       c9                      leaveq 
  400501:       c3                      retq   
  400502:       90                      nop
  400503:       90                      nop

0000000000400504 <main>:
  400504:       55                      push   %rbp
  400505:       48 89 e5                mov    %rsp,%rbp
  400508:       48 83 ec 20             sub    $0x20,%rsp
  40050c:       89 7d ec                mov    %edi,-0x14(%rbp)
  40050f:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
  400513:       c7 45 fc 03 00 00 00    movl   $0x3,-0x4(%rbp)
  40051a:       bf 78 06 40 00          mov    $0x400678,%edi
  40051f:       e8 dc fe ff ff          callq  400400 <puts@plt>
  400524:       8b 15 2a 04 20 00       mov    0x20042a(%rip),%edx        # 600954 <global_data>
  40052a:       b8 84 06 40 00          mov    $0x400684,%eax
  40052f:       89 d6                   mov    %edx,%esi
  400531:       48 89 c7                mov    %rax,%rdi
  400534:       b8 00 00 00 00          mov    $0x0,%eax
  400539:       e8 b2 fe ff ff          callq  4003f0 <printf@plt>
  40053e:       8b 15 24 04 20 00       mov    0x200424(%rip),%edx        # 600968 <global_data_2>
  400544:       b8 96 06 40 00          mov    $0x400696,%eax
  400549:       89 d6                   mov    %edx,%esi
  40054b:       48 89 c7                mov    %rax,%rdi
  40054e:       b8 00 00 00 00          mov    $0x0,%eax
  400553:       e8 98 fe ff ff          callq  4003f0 <printf@plt>
  400558:       b8 aa 06 40 00          mov    $0x4006aa,%eax
  40055d:       8b 55 fc                mov    -0x4(%rbp),%edx
  400560:       89 d6                   mov    %edx,%esi
  400562:       48 89 c7                mov    %rax,%rdi
  400565:       b8 00 00 00 00          mov    $0x0,%eax
  40056a:       e8 81 fe ff ff          callq  4003f0 <printf@plt>
  40056f:       b8 00 00 00 00          mov    $0x0,%eax
  400574:       c9                      leaveq 
  400575:       c3                      retq   
  400576:       90                      nop
  400577:       90                      nop
  400578:       90                      nop
  400579:       90                      nop
  40057a:       90                      nop
  40057b:       90                      nop
  40057c:       90                      nop
  40057d:       90                      nop
  40057e:       90                      nop
  40057f:       90                      nop

0000000000400580 <__libc_csu_fini>:
  400580:       f3 c3                   repz retq 
  400582:       66 66 66 66 66 2e 0f    data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
  400589:       1f 84 00 00 00 00 00 

0000000000400590 <__libc_csu_init>:
  400590:       48 89 6c 24 d8          mov    %rbp,-0x28(%rsp)
  400595:       4c 89 64 24 e0          mov    %r12,-0x20(%rsp)
  40059a:       48 8d 2d bb 01 20 00    lea    0x2001bb(%rip),%rbp        # 60075c <__init_array_end>
  4005a1:       4c 8d 25 b4 01 20 00    lea    0x2001b4(%rip),%r12        # 60075c <__init_array_end>
  4005a8:       4c 89 6c 24 e8          mov    %r13,-0x18(%rsp)
  4005ad:       4c 89 74 24 f0          mov    %r14,-0x10(%rsp)
  4005b2:       4c 89 7c 24 f8          mov    %r15,-0x8(%rsp)
  4005b7:       48 89 5c 24 d0          mov    %rbx,-0x30(%rsp)
  4005bc:       48 83 ec 38             sub    $0x38,%rsp
  4005c0:       4c 29 e5                sub    %r12,%rbp
  4005c3:       41 89 fd                mov    %edi,%r13d
  4005c6:       49 89 f6                mov    %rsi,%r14
  4005c9:       48 c1 fd 03             sar    $0x3,%rbp
  4005cd:       49 89 d7                mov    %rdx,%r15
  4005d0:       e8 f3 fd ff ff          callq  4003c8 <_init>
  4005d5:       48 85 ed                test   %rbp,%rbp
  4005d8:       74 1c                   je     4005f6 <__libc_csu_init+0x66>
  4005da:       31 db                   xor    %ebx,%ebx
  4005dc:       0f 1f 40 00             nopl   0x0(%rax)
  4005e0:       4c 89 fa                mov    %r15,%rdx
  4005e3:       4c 89 f6                mov    %r14,%rsi
  4005e6:       44 89 ef                mov    %r13d,%edi
  4005e9:       41 ff 14 dc             callq  *(%r12,%rbx,8)
  4005ed:       48 83 c3 01             add    $0x1,%rbx
  4005f1:       48 39 eb                cmp    %rbp,%rbx
  4005f4:       72 ea                   jb     4005e0 <__libc_csu_init+0x50>
  4005f6:       48 8b 5c 24 08          mov    0x8(%rsp),%rbx
  4005fb:       48 8b 6c 24 10          mov    0x10(%rsp),%rbp
  400600:       4c 8b 64 24 18          mov    0x18(%rsp),%r12
  400605:       4c 8b 6c 24 20          mov    0x20(%rsp),%r13
  40060a:       4c 8b 74 24 28          mov    0x28(%rsp),%r14
  40060f:       4c 8b 7c 24 30          mov    0x30(%rsp),%r15
  400614:       48 83 c4 38             add    $0x38,%rsp
  400618:       c3                      retq   
  400619:       90                      nop
  40061a:       90                      nop
  40061b:       90                      nop
  40061c:       90                      nop
  40061d:       90                      nop
  40061e:       90                      nop
  40061f:       90                      nop

0000000000400620 <__do_global_ctors_aux>:
  400620:       55                      push   %rbp
  400621:       48 89 e5                mov    %rsp,%rbp
  400624:       53                      push   %rbx
  400625:       48 83 ec 08             sub    $0x8,%rsp
  400629:       48 8b 05 30 01 20 00    mov    0x200130(%rip),%rax        # 600760 <__CTOR_LIST__>
  400630:       48 83 f8 ff             cmp    $0xffffffffffffffff,%rax
  400634:       74 19                   je     40064f <__do_global_ctors_aux+0x2f>
  400636:       bb 60 07 60 00          mov    $0x600760,%ebx
  40063b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
  400640:       48 83 eb 08             sub    $0x8,%rbx
  400644:       ff d0                   callq  *%rax
  400646:       48 8b 03                mov    (%rbx),%rax
  400649:       48 83 f8 ff             cmp    $0xffffffffffffffff,%rax
  40064d:       75 f1                   jne    400640 <__do_global_ctors_aux+0x20>
  40064f:       48 83 c4 08             add    $0x8,%rsp
  400653:       5b                      pop    %rbx
  400654:       c9                      leaveq 
  400655:       c3                      retq   
  400656:       90                      nop
  400657:       90                      nop

下面使用objdump反彙編檢視.data的內容:
$objdump -d -j .data test
.data區儲存的是初始化的全域性變數。

test:     file format elf64-x86-64


Disassembly of section .data:

0000000000600950 <__data_start>:
  600950:       00 00                   add    %al,(%rax)
        ...

0000000000600954 <global_data>:
  600954:       04 00 00 00  

下面使用objdump反彙編檢視.bss的內容:
$objdump -d -j .bss test
.bss區儲存的是未初始化的全域性變數,linux會預設將未初始化的變數置為0。


test:     file format elf64-x86-64


Disassembly of section .bss:

0000000000600958 <completed.6347>:
        ...

0000000000600960 <dtor_idx.6349>:
        ...

0000000000600968 <global_data_2>:
        ...

下面命令可以看到test檔案中所有的符號:
$readelf -s test
Value的值是符號的地址。

Symbol table '.dynsym' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)

Symbol table '.symtab' contains 67 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000400200     0 SECTION LOCAL  DEFAULT    1 
     2: 000000000040021c     0 SECTION LOCAL  DEFAULT    2 
     3: 000000000040023c     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000400260     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000400280     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000004002f8     0 SECTION LOCAL  DEFAULT    6 
     7: 000000000040033c     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000400348     0 SECTION LOCAL  DEFAULT    8 
     9: 0000000000400368     0 SECTION LOCAL  DEFAULT    9 
    10: 0000000000400380     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000004003c8     0 SECTION LOCAL  DEFAULT   11 
    12: 00000000004003e0     0 SECTION LOCAL  DEFAULT   12 
    13: 0000000000400420     0 SECTION LOCAL  DEFAULT   13 
    14: 0000000000400658     0 SECTION LOCAL  DEFAULT   14 
    15: 0000000000400668     0 SECTION LOCAL  DEFAULT   15 
    16: 00000000004006bc     0 SECTION LOCAL  DEFAULT   16 
    17: 00000000004006e0     0 SECTION LOCAL  DEFAULT   17 
    18: 0000000000600760     0 SECTION LOCAL  DEFAULT   18 
    19: 0000000000600770     0 SECTION LOCAL  DEFAULT   19 
    20: 0000000000600780     0 SECTION LOCAL  DEFAULT   20 
    21: 0000000000600788     0 SECTION LOCAL  DEFAULT   21 
    22: 0000000000600918     0 SECTION LOCAL  DEFAULT   22 
    23: 0000000000600920     0 SECTION LOCAL  DEFAULT   23 
    24: 0000000000600950     0 SECTION LOCAL  DEFAULT   24 
    25: 0000000000600958     0 SECTION LOCAL  DEFAULT   25 
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   26 
    27: 000000000040044c     0 FUNC    LOCAL  DEFAULT   13 call_gmon_start
    28: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    29: 0000000000600760     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_LIST__
    30: 0000000000600770     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_LIST__
    31: 0000000000600780     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    32: 0000000000400470     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    33: 0000000000600958     1 OBJECT  LOCAL  DEFAULT   25 completed.6347
    34: 0000000000600960     8 OBJECT  LOCAL  DEFAULT   25 dtor_idx.6349
    35: 00000000004004e0     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    36: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    37: 0000000000600768     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_END__
    38: 0000000000400758     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    39: 0000000000600780     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    40: 0000000000400620     0 FUNC    LOCAL  DEFAULT   13 __do_global_ctors_aux
    41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
    42: 0000000000600920     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    43: 000000000060075c     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    44: 000000000060075c     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    45: 0000000000600788     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    46: 0000000000600950     0 NOTYPE  WEAK   DEFAULT   24 data_start
    47: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
    48: 0000000000400580     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    49: 0000000000400420     0 FUNC    GLOBAL DEFAULT   13 _start
    50: 0000000000600968     4 OBJECT  GLOBAL DEFAULT   25 global_data_2
    51: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    52: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    53: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.2.5
    54: 0000000000400658     0 FUNC    GLOBAL DEFAULT   14 _fini
    55: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    56: 0000000000400668     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    57: 0000000000600950     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    58: 0000000000400670     0 OBJECT  GLOBAL HIDDEN    15 __dso_handle
    59: 0000000000600778     0 OBJECT  GLOBAL HIDDEN    19 __DTOR_END__
    60: 0000000000400590   137 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    61: 0000000000600958     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    62: 0000000000600970     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    63: 0000000000600958     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    64: 0000000000600954     4 OBJECT  GLOBAL DEFAULT   24 global_data
    65: 0000000000400504   114 FUNC    GLOBAL DEFAULT   13 main
    66: 00000000004003c8     0 FUNC    GLOBAL DEFAULT   11 _init

下面命令來檢視檔案的段資訊:
$readelf -l test
區到段的對映,基本上是按照區的順序進行對映。
如果Flags為R和E,表示該段可讀和可執行。
如果Flags為W,表示該段可寫。
VirtAddr是每個段的虛擬起始地址。這個地址並不是位於真正記憶體上的地址(實體地址)。

Elf file type is EXEC (Executable file)
Entry point 0x400420
There are 8 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001c0 0x00000000000001c0  R E    8
  INTERP         0x0000000000000200 0x0000000000400200 0x0000000000400200
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000000075c 0x000000000000075c  R E    200000
  LOAD           0x0000000000000760 0x0000000000600760 0x0000000000600760
                 0x00000000000001f8 0x0000000000000210  RW     200000
  DYNAMIC        0x0000000000000788 0x0000000000600788 0x0000000000600788
                 0x0000000000000190 0x0000000000000190  RW     8
  NOTE           0x000000000000021c 0x000000000040021c 0x000000000040021c
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000006bc 0x00000000004006bc 0x00000000004006bc
                 0x0000000000000024 0x0000000000000024  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     8

 Section 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 .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .ctors .dtors .jcr .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     

如上所示,段有多種型別,下面介紹LOAD型別
LOAD:該段的內容從可執行檔案中獲取。Offset標識核心從檔案讀取的位置。FileSiz標識讀取多少位元組。

那麼,執行test之後的程式的段佈局是如何呢?
可以通過cat /proc/pid/maps來檢視。pid是程式的pid。
但是該test執行時間很短,可以使用gdb加斷點來執行,或者在return語句之前加上sleep()。

下面使用gdb加斷點的形式:

GNU gdb (GDB) Red Hat Enterprise Linux (7.2-50.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /data/readyao/qqlive_zb_prj/server/cgi_push_post_replay/lib/test...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x400508
(gdb) r
Starting program: /data/readyao/qqlive_zb_prj/server/cgi_push_post_replay/lib/test 
[Thread debugging using libthread_db enabled]

Breakpoint 1, 0x0000000000400508 in main ()
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.49.tl1.x86_64

$cat /proc/6929/maps

00400000-00401000 r-xp 00000000 ca:11 8626925                            /test
00600000-00601000 rw-p 00000000 ca:11 8626925                            /test
7ffff762d000-7ffff7644000 r-xp 00000000 ca:01 332328                     /lib64/libpthread-2.12.so
7ffff7644000-7ffff7843000 ---p 00017000 ca:01 332328                     /lib64/libpthread-2.12.so
7ffff7843000-7ffff7844000 r--p 00016000 ca:01 332328                     /lib64/libpthread-2.12.so
7ffff7844000-7ffff7845000 rw-p 00017000 ca:01 332328                     /lib64/libpthread-2.12.so
7ffff7845000-7ffff7849000 rw-p 00000000 00:00 0 
7ffff7849000-7ffff784b000 r-xp 00000000 ca:01 332237                     /lib64/libdl-2.12.so
7ffff784b000-7ffff7a4b000 ---p 00002000 ca:01 332237                     /lib64/libdl-2.12.so
7ffff7a4b000-7ffff7a4c000 r--p 00002000 ca:01 332237                     /lib64/libdl-2.12.so
7ffff7a4c000-7ffff7a4d000 rw-p 00003000 ca:01 332237                     /lib64/libdl-2.12.so
7ffff7a4d000-7ffff7bd3000 r-xp 00000000 ca:01 332102                     /lib64/libc-2.12.so
7ffff7bd3000-7ffff7dd3000 ---p 00186000 ca:01 332102                     /lib64/libc-2.12.so
7ffff7dd3000-7ffff7dd7000 r--p 00186000 ca:01 332102                     /lib64/libc-2.12.so
7ffff7dd7000-7ffff7dd8000 rw-p 0018a000 ca:01 332102                     /lib64/libc-2.12.so
7ffff7dd8000-7ffff7ddd000 rw-p 00000000 00:00 0 
7ffff7ddd000-7ffff7dfd000 r-xp 00000000 ca:01 332126                     /lib64/ld-2.12.so
7ffff7ed9000-7ffff7edc000 rw-p 00000000 00:00 0 
7ffff7eeb000-7ffff7eee000 r-xp 00000000 ca:01 336319                     /lib64/libonion_security.so.1.0.13
7ffff7eee000-7ffff7fee000 ---p 00003000 ca:01 336319                     /lib64/libonion_security.so.1.0.13
7ffff7fee000-7ffff7fef000 rw-p 00003000 ca:01 336319                     /lib64/libonion_security.so.1.0.13
7ffff7fef000-7ffff7ffb000 rw-p 00000000 00:00 0 
7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 0001f000 ca:01 332126                     /lib64/ld-2.12.so
7ffff7ffd000-7ffff7ffe000 rw-p 00020000 ca:01 332126                     /lib64/ld-2.12.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffea000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

前面一部分是VMA的起始地址和結束地址。
最後一部分是該區域內容所屬檔案。
在32位系統中,程式地址空間為4G,分為使用者空間和核心空間。
這裡寫圖片描述
從下面可以看到棧的地址是向下生長,堆的地址是向上生長。
這裡寫圖片描述

參考資料:
http://www.linuxforums.org/articles/understanding-elf-using-readelf-and-objdump_125.html

http://www.linuxjournal.com/article/1059
http://www.linuxjournal.com/article/1060
Two good ELF introductory articles written by Eric Youngdale.

http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
Explanation about ELF from Wikipedia. From there, you can find links to another useful documents.

http://x86.ddj.com/ftp/manuals/tools/elf.pdf
The document that completely explain all about ELF structure. Study this document after reading this article to gain complete insight about ELF.

ELFSH
A tool to do ELF binary inspection and manipulation. Pretty useful for reverse engineering too. It has scripting feature so you can automate most of your work. In the website, there are many documents that explains various ELF hacking.

相關文章