乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      計算機原理系列之二 ——

       xiaofenglib 2020-09-16

      下面我們介紹一種文件格式:ELF格式,全名為可執(zhí)行和可鏈接格式(Executable and Linkable Format)。維基百科中這樣描述:

      在計算機科學(xué)中,ELF文件是一種用于可執(zhí)行文件、目標(biāo)文件、共享庫和核心轉(zhuǎn)儲(core dump)的標(biāo)準(zhǔn)文件格式。其中核心轉(zhuǎn)儲是指: 操作系統(tǒng)在進程收到某些信號而終止時,將此時進程地址空間的內(nèi)容以及有關(guān)進程狀態(tài)的其他信息寫出的一個磁盤文件。這種信息往往用于調(diào)試。

      一、ELF文件類型

      通俗點說由匯編器和鏈接器生成的文件都屬于ELF文件。通常我們接觸的ELF文件主要有以下三類:

      • 可重定位文件relocatable file) 它保存了一些可以和其他目標(biāo)文件鏈接并生成可執(zhí)行文件或者共享庫的二進制代碼和數(shù)據(jù)。

      • 可執(zhí)行文件excutable file)它保存了適合直接加載到內(nèi)存中執(zhí)行的二進制程序。

      • 共享庫文件shared object file)一種特殊的可重定位目標(biāo)文件,可以在加載或者運行時被動態(tài)的加載進內(nèi)存并鏈接。

      總之,ELF文件是一種文件格式。但凡是一種格式,總要有一些規(guī)則,下面我們來介紹ELF文件的格式規(guī)則。

      二、ELF文件結(jié)構(gòu)

      一個典型的ELF文件包括ELF Header、Sections、Section Header TableProgram Header Table。其位置分布如下圖所示:
      01-elf
      圖1 ELF文件構(gòu)成

      1. ELF Header

      每個ELF文件都存在一個ELF Header用來描述其結(jié)構(gòu)和組成。ELF Header其實對應(yīng)的是一個結(jié)構(gòu)體,該結(jié)構(gòu)體定義如下:

      #define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; ElfN_Addr e_entry; ElfN_Off e_phoff; ElfN_Off e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } ElfN_Ehdr;

      其中

      ElfN_Addr       Unsigned program address, uintN_tElfN_Off        Unsigned file offset, uintN_t

      上述結(jié)構(gòu)體的各成員意義如下:

      • e_ident:包含一個magic number、ABI信息,該文件使用的平臺、大小端規(guī)則

      • e_type:文件類型, 表示該文件屬于可執(zhí)行文件、可重定位文件、core dump文件或者共享庫

      • e_machine:機器類型

      • e_version:通常都是1

      • e_entry: 表示程序執(zhí)行的入口地址

      • e_phoff: 表示Program Header的入口偏移量(以字節(jié)為單位)

      • e_shoff: 表示Section Header的入口偏移量(以字節(jié)為單位)

      • e_flags: 保存了這個ELF文件相關(guān)的特定處理器的flag

      • e_ehsize: 表示ELF Header大?。ㄒ宰止?jié)為單位)

      • e_phentsize: 表示Program Header大?。ㄒ宰止?jié)為單位)

      • e_phnum: 表示Program Header的數(shù)量 (十進制數(shù)字)

      • e_shentsize: 表示Section Header大?。ㄒ宰止?jié)為單位)

      • e_shnum: 表示Section Header的數(shù)量 (十進制數(shù)字)

      • e_shstrndx: 表示字符串表的索引,字符串表用來保存ELF文件中的字符串,比如段名、變量名。 然后通過字符串在表中的偏移訪問字符串。

      例如,machine的值為0x3e, 十進制為62,其代表的意義可以從文件elf-em.h中找到,如下:

      #define EM_X86_64 62 /* AMD x86-64 */

      表示,這個ELF文件可以運行在x86_64的機器上。

      2. Section

      在ELF文件中,數(shù)據(jù)和代碼分開存放的,這樣可以按照其功能屬性分成一些區(qū)域,比如程序、數(shù)據(jù)、符號表等。這些分離存放的區(qū)域在ELF文件中反映成section。ELF文件中典型的section如下:

      • .text: 已編譯程序的二進制代碼

      • .rodata: 只讀數(shù)據(jù)段,比如常量

      • .data: 已初始化的全局變量和靜態(tài)變量

      • .bss: 未初始化的全局變量和靜態(tài)變量,所有被初始化成0的全局變量和靜態(tài)變量

      • .sysmtab: 符號表,它存放了程序中定義和引用的函數(shù)和全局變量的信息

      • .debug: 調(diào)試符號表,它需要以'-g'選項編譯才能得到,里面保存了程序中定義的局部變量和類型定義,程序中定義和引用的全局變量,以及原始的C文件

      • .line: 原始的C文件行號和.text節(jié)中機器指令之間的映射

      • .strtab: 字符串表,內(nèi)容包括.symtab.debug節(jié)中的符號表

      特殊的,
      1)對于可重定位的文件,由于在編譯時,并不能確定它引用的外部函數(shù)和變量的地址信息,因此,編譯器在生成目標(biāo)文件時,增加了兩個section:

      • .rel.text 保存了程序中引用的外部函數(shù)的重定位信息,這些信息用于在鏈接時重定位其對應(yīng)的符號。

      • .rel.data 保存了被模塊引用或定義的所有全局變量的重定位信息,這些信息用于在鏈接時重定位其對應(yīng)的全局變量。

      2)對于可執(zhí)行文件,由于它已經(jīng)全部完成了重定位工作,可以直接加載到內(nèi)存中執(zhí)行,所以它不存在.rel.text.rel.data這兩個section。但是,它增加了一個section:

      • .init: 這個section里面保存了程序運行前的初始化代碼

      上述描述的各個文件中包含的這些section是必須存在的,當(dāng)然除了這些section,每種文件還有一些其他的section用來存放編譯器或者鏈接器所需要的輔助信息,詳情請參考參考閱讀1,在這里就不過多的討論了。

      3. Section Header Table

      上述各個section的大小和位置等具體信息的存放是由Section Header Table來描述的。Section Header Table是一個結(jié)構(gòu)體數(shù)組,對應(yīng)的結(jié)構(gòu)體定義如下:

      typedef struct {    uint32_t   sh_name;    uint32_t   sh_type;    uint64_t   sh_flags;    Elf64_Addr sh_addr;    Elf64_Off  sh_offset;    uint64_t   sh_size;    uint32_t   sh_link;    uint32_t   sh_info;    uint64_t   sh_addralign;    uint64_t   sh_entsize;} Elf64_Shdr;

      其中各成員的意義如下:

      • sh_name:表示該section的名字相對于.shstrtab section的地址偏移量。

      • sh_type:表示該section中存放的內(nèi)容類型,比如符號表,可重定位段等。

      • sh_flags: 表示該section的一些屬性,比如是否可寫,可執(zhí)行等。

      • sh_addr: 表示該section在程序運行時的內(nèi)存地址

      • sh_offset: 表示該section相對于ELF文件起始地址的偏移量

      • sh_size: 表示該section的大小

      • sh_link: 配合sh_info保存section的額外信息

      • sh_info:保存該section相關(guān)的一些額外信息

      • sh_addralign:表示該section需要的地址對齊信息

      • sh_entsize:有些section里保存的是一些固定長度的條目,比如符號表。對于這些section來講,sh_entsize里保存的就是條目的長度。

      4. Program Header Table

      前面講過了,section基本是按照目標(biāo)文件內(nèi)容的功能來劃分的一些區(qū)域,而根據(jù)其內(nèi)容在內(nèi)存中是否可讀寫等屬性,又可以將不同的section劃分成不同的segment。其中每個segment可以由一個或多個section組成。其關(guān)系如圖1所示。

      在可執(zhí)行文件中,ELF header下面緊接著就是Program Header Table。它描述了各個segment在ELF文件中的位置以及在程序執(zhí)行過程中系統(tǒng)需要準(zhǔn)備的其他信息。它也是用一個結(jié)構(gòu)體數(shù)組來表示的。具體代碼如下:

      typedef uint64_t Elf64_Addr;typedef uint64_t Elf64_Off;typedef uint32_t Elf64_Word;typedef uint64_t Elf64_Xword;typedef struct { Elf64_Word p_type; // 4 Elf64_Word p_flags; // 4 Elf64_Off p_offset; // 8 Elf64_Addr p_vaddr; // 8 Elf64_Addr p_paddr; // 8 Elf64_Xword p_filesz; // 8 Elf64_Xword p_memsz; // 8 Elf64_Xword p_align; // 8} Elf64_Phdr;

      各個字段的具體含義如下:

      • p_type:描述了當(dāng)前segment是何種類型的或者如何解釋當(dāng)前segment,比如是動態(tài)鏈接相關(guān)的或者可加載類型的等

      • p_flags:保存了該segment的flag

      • p_offset:表示從ELF文件到該segment第一個字節(jié)的偏移量

      • p_vaddr:表示該segment的第一個字節(jié)在內(nèi)存中的虛擬地址

      • p_paddr:對于使用物理地址的系統(tǒng)來講,這個成員表示該segment的物理地址

      • p_filesz:表示該segment的大小,以字節(jié)表示

      • p_memsz:表示該segment在內(nèi)存中的大小,以字節(jié)表示

      • p_align:表示該segment在文件中或者內(nèi)存中需要以多少字節(jié)對齊

      三、實踐

      為了進一步加深對ELF文件整體結(jié)構(gòu)的理解,我們?nèi)∫粋€64bit的linux上的可執(zhí)行文件hello來驗證。
      首先,使用READELF工具查看其ELF Header信息:

      $ readelf -h helloELF 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:               0x400430  Start of program headers:          64 (bytes into file)  Start of section headers:          6616 (bytes into file)  Flags:                             0x0  Size of this header:               64 (bytes)  Size of program headers:           56 (bytes)  Number of program headers:         9  Size of section headers:           64 (bytes)  Number of section headers:         31  Section header string table index: 28

      從ELF Header中我們得到如下信息:

      • ELF Header大?。?code>Size of this header)為64 byte

      • Program Header Table的起始地址(Start of program headers)是64 byte,其內(nèi)部共有9個(Number of program headers)Program Header,每個大小為56 byte(Size of program headers

      • Section Header Table的起始地址(Start of section headers)是6616 byte,其內(nèi)部共有31個(Number of section headers)Section Header,每個大小為64 byte(Size of this header

      其次,使用READELF命令讀取section header table信息:

      $ readelf -S helloThere are 31 section headers, starting at offset 0x19d8: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 0000000000400238 00000238 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000400254 00000254 0000000000000020 0000000000000000 A 0 0 4 [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274 0000000000000024 0000000000000000 A 0 0 4 ... snip ... [27] .comment PROGBITS 0000000000000000 00001038 0000000000000035 0000000000000001 MS 0 0 1 [28] .shstrtab STRTAB 0000000000000000 000018cc 000000000000010c 0000000000000000 0 0 1 [29] .symtab SYMTAB 0000000000000000 00001070 0000000000000648 0000000000000018 30 47 8 [30] .strtab STRTAB 0000000000000000 000016b8 0000000000000214 0000000000000000 0 0 1Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)

      根據(jù)上述section信息,我們得到:

      • section的起始地址是0x238(第一個section .interp的起始地址)

      • section的結(jié)束地址是.shstrtab的結(jié)束地址即:0x18cc + 0x10c = 0x19d8

      根據(jù)我們上面的結(jié)論,我們可以得到該ELF文件的組成圖如下:

      namestart_addrsizeend_addr
      ELF Header00x40
      Program Header Table0x400x1F8
      Section0x238
      0x19D8
      Section Header Table0x19D80x7C0

      我們可以計算出各部分的end_addr上述空白部分,得到:

      cs02-table

      顯然,各個section正好和下一個section首尾相接。然后,通過ls -l hello命令查看該二進制文件的大小,得到該文件大小為8600 byte,而Section Header Table的end_addr 0x2198換算成十進制大小正好是8600 byte。從而證明我們上述的分析是沒問題的。

      四、總結(jié)

      1. ELF文件包括可重定位文件、可執(zhí)行文件、共享庫和Core dump文件。其基本結(jié)構(gòu)包括ELF Header,Program Header Table,Sections和Section Header Table。其中不同的sections組成了不同的segment。

      2. ELF Header描述了該ELF文件中Program Header Table的位置、大小,Section Header Table的位置、大小和程序執(zhí)行的入口地址等信息。

      3. Program Header Table描述了各個segment的類型、虛擬地址、相對文件的偏移地址等信息。

      4. Section Header Table描述了各個section的名字、類型、相對文件的偏移地址等信息。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多