Linux 可执行文件 ELF结构 及程序加载运行
?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,具體原因以后再分析。
????第三個緊接著是堆。用于動態分配內存。
????第四個是棧。用于存放局部變量。
????整體的結構如下圖:
????程序運行的過程:建立虛擬空間(分配一個頁目錄)-> 建立虛擬空間與可執行文件映射(頁目錄項指向磁盤的程序) -> 跳到程序入口 -> 缺頁異常-> 在內存中尋找空閑頁,將對應的頁換入 -> 建立映射 -> 開始執行。
原文:https://blog.csdn.net/jltxgcy/article/details/39233689?
?
總結
以上是生活随笔為你收集整理的Linux 可执行文件 ELF结构 及程序加载运行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成都大熊猫基地下午去怎么样
- 下一篇: IDA——动态调试Linux上的ELF文