Linux 可執行檔 ELF結構 及程式載入運行

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   使用   ar   檔案   資料   

    Linux下ELF檔案類型分為以下幾種:

    1、可重定位檔案,例如SimpleSection.o;

    2、可執行檔,例如/bin/bash;

    3、共用目標檔案,例如/lib/libc.so。


    在Linux 可重定位檔案 ELF結構一文中,我們已經分析了可重定位檔案ELF結構。本文分析可執行檔的ELF結構。


    首先附上原始碼:

    SectionMapping.c 

#include <stdlib.h>int main(){while(1){sleep(1000);}return 0;}

    使用命令gcc -static SectionMapping.c -o SectionMapping.elf,靜態連結為可執行檔。


    接著使用命令readelf -S SectionMapping.elf得到Section Table。如下:

There are 33 section headers, starting at offset 0xc3878:Section Headers:  [Nr] Name              Type             Address           Offset       Size              EntSize          Flags  Link  Info  Align  [ 0]                   NULL             0000000000000000  00000000       0000000000000000  0000000000000000           0     0     0  [ 1] .note.ABI-tag     NOTE             0000000000400190  00000190       0000000000000020  0000000000000000   A       0     0     4  [ 2] .note.gnu.build-i NOTE             00000000004001b0  000001b0       0000000000000024  0000000000000000   A       0     0     4  [ 3] .rela.plt         RELA             00000000004001d8  000001d8       0000000000000120  0000000000000018   A       0     5     8  [ 4] .init             PROGBITS         00000000004002f8  000002f8       0000000000000018  0000000000000000  AX       0     0     4  [ 5] .plt              PROGBITS         0000000000400310  00000310       00000000000000c0  0000000000000000  AX       0     0     16  [ 6] .text             PROGBITS         00000000004003d0  000003d0       0000000000094988  0000000000000000  AX       0     0     16  [ 7] __libc_thread_fre PROGBITS         0000000000494d60  00094d60       00000000000000a8  0000000000000000  AX       0     0     16  [ 8] __libc_freeres_fn PROGBITS         0000000000494e10  00094e10       000000000000181c  0000000000000000  AX       0     0     16  [ 9] .fini             PROGBITS         000000000049662c  0009662c       000000000000000e  0000000000000000  AX       0     0     4  [10] .rodata           PROGBITS         0000000000496640  00096640       000000000001d344  0000000000000000   A       0     0     32  [11] __libc_thread_sub PROGBITS         00000000004b3988  000b3988       0000000000000008  0000000000000000   A       0     0     8  [12] __libc_subfreeres PROGBITS         00000000004b3990  000b3990       0000000000000058  0000000000000000   A       0     0     8  [13] __libc_atexit     PROGBITS         00000000004b39e8  000b39e8       0000000000000008  0000000000000000   A       0     0     8  [14] .eh_frame         PROGBITS         00000000004b39f0  000b39f0       000000000000d4c4  0000000000000000   A       0     0     8  [15] .gcc_except_table PROGBITS         00000000004c0eb4  000c0eb4       0000000000000172  0000000000000000   A       0     0     1  [16] .tdata            PROGBITS         00000000006c1ef0  000c1ef0       0000000000000020  0000000000000000 WAT       0     0     16  [17] .tbss             NOBITS           00000000006c1f10  000c1f10       0000000000000038  0000000000000000 WAT       0     0     16  [18] .init_array       INIT_ARRAY       00000000006c1f10  000c1f10       0000000000000008  0000000000000000  WA       0     0     8  [19] .fini_array       FINI_ARRAY       00000000006c1f18  000c1f18       0000000000000008  0000000000000000  WA       0     0     8  [20] .ctors            PROGBITS         00000000006c1f20  000c1f20       0000000000000010  0000000000000000  WA       0     0     8  [21] .dtors            PROGBITS         00000000006c1f30  000c1f30       0000000000000010  0000000000000000  WA       0     0     8  [22] .jcr              PROGBITS         00000000006c1f40  000c1f40       0000000000000008  0000000000000000  WA       0     0     8  [23] .data.rel.ro      PROGBITS         00000000006c1f50  000c1f50       0000000000000080  0000000000000000  WA       0     0     16  [24] .got              PROGBITS         00000000006c1fd0  000c1fd0       0000000000000010  0000000000000008  WA       0     0     8  [25] .got.plt          PROGBITS         00000000006c1fe8  000c1fe8       0000000000000078  0000000000000008  WA       0     0     8  [26] .data             PROGBITS         00000000006c2060  000c2060       0000000000001690  0000000000000000  WA       0     0     32  [27] .bss              NOBITS           00000000006c3700  000c36f0       0000000000002ba8  0000000000000000  WA       0     0     32  [28] __libc_freeres_pt NOBITS           00000000006c62b0  000c36f0       0000000000000048  0000000000000000  WA       0     0     16  [29] .comment          PROGBITS         0000000000000000  000c36f0       000000000000002a  0000000000000001  MS       0     0     1  [30] .shstrtab         STRTAB           0000000000000000  000c371a       000000000000015b  0000000000000000           0     0     1  [31] .symtab           SYMTAB           0000000000000000  000c40b8       000000000000c168  0000000000000018          32   870     8  [32] .strtab           STRTAB           0000000000000000  000d0220       0000000000007a26  0000000000000000           0     0     1

                                     表 1

    這個可執行檔共有33個Section。


    接著我們使用readelf -h SectionMapping.elf,讀取elf可執行檔頭部資訊。如:


                                     圖 1


    可以對比,Linux 可重定位檔案 ELF結構,這裡多了program header。

    Entry point address:程式的入口地址是0x401058,使用objdump -d SectionMapping.elf | less,可以查看到程式的入口地址是<_start>。如:


                                           圖 2

    Start of program headers:program headers的位移,由於標頭檔大小為64,所以program headers緊挨著標頭檔存放。

    Size of program headers:program headers的大小。為56個位元組。

    Number of section headers:program headers的數量。為6個。

    在表1中,第一個section在檔案中的位移是0x190,標頭檔大小為64 + program header大小為56 * program header數量6 = 400 = 0x190。


    然後,我們使用命令readelf -l SectionMapping.elf,我們會得到program header部分。如:


                                 圖  3


    可見,分為6個Segment。注意表1中每個段叫Section。

    Offset:這個Segment在檔案中位移。

    VirtAddr:這個Segment在虛擬位址的位移。

    FileSiz:在ELF檔案中所佔的長度。

    MemSiz:在進程虛擬空間所佔的長度。

    我們發現第二個Segment,MemSiz > FileSiz,表示在記憶體中分配的空間大小超過檔案實際大小。超過的部分全部初始化為0,作為BSS段。因為資料區段和BSS段的唯一區別是,資料區段從檔案中初始化內容,BSS段內容全部初始化為0。


    我們主要關心前兩個Segment,第一個是程式碼片段,虛擬位址從0x00400000到0x004c1026。檔案位移從0x00000000到0x000c1026。

    第二個是資料區段,虛擬位址為從0x006c1ef0到0x006c1ef0+0x4408=0x6c62f8。檔案位移從0x000c1ef0到0x000c1ef0+0x1800=0x000C36f0。

    結合表1和兩個Segment的檔案位移,可以得出:

    第一個Segment從第0個Section到第15個Section。(0x00000000-0x000c1026)

  [Nr] Name              Type             Address           Offset       Size              EntSize          Flags  Link  Info  Align  [ 0]                   NULL             0000000000000000  00000000       0000000000000000  0000000000000000           0     0     0  [ 1] .note.ABI-tag     NOTE             0000000000400190  00000190       0000000000000020  0000000000000000   A       0     0     4  [ 2] .note.gnu.build-i NOTE             00000000004001b0  000001b0       0000000000000024  0000000000000000   A       0     0     4  [ 3] .rela.plt         RELA             00000000004001d8  000001d8       0000000000000120  0000000000000018   A       0     5     8  [ 4] .init             PROGBITS         00000000004002f8  000002f8       0000000000000018  0000000000000000  AX       0     0     4  [ 5] .plt              PROGBITS         0000000000400310  00000310       00000000000000c0  0000000000000000  AX       0     0     16  [ 6] .text             PROGBITS         00000000004003d0  000003d0       0000000000094988  0000000000000000  AX       0     0     16  [ 7] __libc_thread_fre PROGBITS         0000000000494d60  00094d60       00000000000000a8  0000000000000000  AX       0     0     16  [ 8] __libc_freeres_fn PROGBITS         0000000000494e10  00094e10       000000000000181c  0000000000000000  AX       0     0     16  [ 9] .fini             PROGBITS         000000000049662c  0009662c       000000000000000e  0000000000000000  AX       0     0     4  [10] .rodata           PROGBITS         0000000000496640  00096640       000000000001d344  0000000000000000   A       0     0     32  [11] __libc_thread_sub PROGBITS         00000000004b3988  000b3988       0000000000000008  0000000000000000   A       0     0     8  [12] __libc_subfreeres PROGBITS         00000000004b3990  000b3990       0000000000000058  0000000000000000   A       0     0     8  [13] __libc_atexit     PROGBITS         00000000004b39e8  000b39e8       0000000000000008  0000000000000000   A       0     0     8  [14] .eh_frame         PROGBITS         00000000004b39f0  000b39f0       000000000000d4c4  0000000000000000   A       0     0     8  [15] .gcc_except_table PROGBITS         00000000004c0eb4  000c0eb4       0000000000000172  0000000000000000   A       0     0     1

    第二個Segment從第16個Section到26個Section。(0x000c1ef0-0x000C36f0)

  [16] .tdata            PROGBITS         00000000006c1ef0  000c1ef0       0000000000000020  0000000000000000 WAT       0     0     16  [17] .tbss             NOBITS           00000000006c1f10  000c1f10       0000000000000038  0000000000000000 WAT       0     0     16  [18] .init_array       INIT_ARRAY       00000000006c1f10  000c1f10       0000000000000008  0000000000000000  WA       0     0     8  [19] .fini_array       FINI_ARRAY       00000000006c1f18  000c1f18       0000000000000008  0000000000000000  WA       0     0     8  [20] .ctors            PROGBITS         00000000006c1f20  000c1f20       0000000000000010  0000000000000000  WA       0     0     8  [21] .dtors            PROGBITS         00000000006c1f30  000c1f30       0000000000000010  0000000000000000  WA       0     0     8  [22] .jcr              PROGBITS         00000000006c1f40  000c1f40       0000000000000008  0000000000000000  WA       0     0     8  [23] .data.rel.ro      PROGBITS         00000000006c1f50  000c1f50       0000000000000080  0000000000000000  WA       0     0     16  [24] .got              PROGBITS         00000000006c1fd0  000c1fd0       0000000000000010  0000000000000008  WA       0     0     8  [25] .got.plt          PROGBITS         00000000006c1fe8  000c1fe8       0000000000000078  0000000000000008  WA       0     0     8  [26] .data             PROGBITS         00000000006c2060  000c2060       0000000000001690  0000000000000000  WA       0     0     32

    以上分析的都是靜態狀態下的程式,下面我們看看動態下的進程的空間是怎麼分配的。

    首先使用命令, ./SectionMapping.elf &,輸出如下:

    

    然後使用命令:cat /proc/2184/maps,輸出如下:


                                    圖 4

    

    靜態時,我們計算出的兩個Segment的虛擬空間的位移分別為:

    第一個是程式碼片段,虛擬位址從0x00400000到0x004c1026。在圖4中,因為要頁面對齊,所以分配了0x400000到0x4c2000。

    第二個是資料區段,虛擬位址為從0x006c1ef0到0x006c1ef0+0x4408=0x6c62f8。在圖4中,因為要頁面對齊,所以分配了0x6c1000到0x6c4000。注意,0x6c62f8大於0x6c4000,具體原因以後再分析。

    第三個緊接著是堆。用於動態分配記憶體。

    第四個是棧。用於存放局部變數。

    整體的結構如:



    程式啟動並執行過程:建立虛擬空間(分配一個頁目錄)-> 建立虛擬空間與可執行檔映射(頁目錄項指向磁碟的程式) -> 跳到程式入口 -> 缺頁異常-> 在記憶體中尋找空閑頁,將對應的頁換入 -> 建立映射 -> 開始執行。

Linux 可執行檔 ELF結構 及程式載入運行

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.