日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ELF文件

發(fā)布時間:2023/12/14 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ELF文件 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

ELF文件

文章目錄

    • ELF文件
  • 前言
  • 一、.out文件的生成
  • 二、ELF格式
    • 1.ELF header
    • 2.section header
    • 3.sections
    • 4.Program header table
  • 三、實驗驗證
  • 四、其他
    • 1、符號表和重定位表
    • 2、鏈接
  • 總結(jié)


前言

最近在看書,看到程序的編譯,鏈接時候感覺得整理下,做下筆記,有些知識點并不是該書的重點,因此他也是提及到而已,但是處于好奇,還是想多知道點,因此也查閱了網(wǎng)上相關(guān)博主的一些文章,將我所需要的做一個整理,這些知識工作中,很少用到,因此也是會經(jīng)常忘。
閱讀文獻(xiàn):
了解過程中,主要是閱讀了《嵌入式c語言自我修養(yǎng)》
網(wǎng)址1:www.luomuxiaoxiao.com
網(wǎng)址2:https://blog.csdn.net/npy_lp/article/details/102604380


一、.out文件的生成

?.out文件是可執(zhí)行文件,它是目標(biāo)文件(object file)的一種。目標(biāo)文件可以分為三種:
?1. 可重定位的目標(biāo)文件
?2.可執(zhí)行的目標(biāo)文件
?3.可被共享的目標(biāo)文件。
?這幾個我們在嵌入式開發(fā)的時候都用到。但是接觸最多的是可執(zhí)行文件。一般的程序編譯的流程:預(yù)處理,編譯,匯編,鏈接。就可以生成一個可執(zhí)行文件。

二、ELF格式

?不管是.out文件還是其他的目標(biāo)文件,他們的文件格式都是ELF格式。
在百科里邊的定義是這樣的:
? ELF在計算機(jī)科學(xué)中,是一種用于二進(jìn)制文件、可執(zhí)行文件、目標(biāo)代碼、共享庫和核心轉(zhuǎn)儲的標(biāo)準(zhǔn)文件格式。添加鏈接描述
所以,本次這篇筆記主要是結(jié)合可執(zhí)行文件來了解ELF文件格式。

?ELF文件由4部分組成,分別是ELF頭(ELF header)、程序頭表(Program header table)、節(jié)(Section)和節(jié)頭表(Section header table)。如下圖1和圖2都是我從百度圖片上下載的。

1.ELF header

?下面是ELF 頭的結(jié)構(gòu)體,從header 可以大致分析出這四個組成部分的布局。可使用命令"readelf -h filename"來察看文件頭的內(nèi)容 可參考的博文

#define EI_NIDENT 16 typedef struct{unsigned char e_ident[EI_NIDENT];Elf32_Half e_type;Elf32_Half e_machine;Elf32_Word e_version;Elf32_Addr e_entry;Elf32_Off e_phoff;Elf32_Off e_shoff;Elf32_Word e_flags;Elf32_Half e_ehsize;Elf32_Half e_phentsize;Elf32_Half e_phnum;Elf32_Half e_shentsize;Elf32_Half e_shnum;Elf32_Half e_shstrndx; } Elf32_Ehdr; 字段描述
e_ident最開頭是16個字節(jié)的e_ident, 其中包含用以表示ELF文件的字符,以及其他一些與機(jī)器無關(guān)的信息。開頭的4個字節(jié)值固定不變,為0x7f和ELF三個字符。
e_type它標(biāo)識的是該文件的類型,可重定位文件為1,可執(zhí)行文件為2,共享文件為3
e_machine表明運行該程序需要的體系結(jié)構(gòu)
e_version表示文件的版本
e_entry程序的入口地址
e_phoff表示Program header table 在文件中的偏移量
e_shoff表示Section header table 在文件中的偏移量
e_flags保存了這個ELF文件相關(guān)的特定處理器的flag
e_ehsize表示ELF header大小,32位ELF是52字節(jié),64位是64字節(jié)。
e_phentsize表示Program header table中每一個條目的大小。
e_phnum表示Program header table中有多少個條目。
e_shentsize表示Section header table中的每一個條目的大小。
e_shnum表示Section header table中有多少個條目。
e_shstrndx包含節(jié)名稱的字符串是第幾個節(jié)

2.section header

?section header用來描述每個section的特性,如大小、類型、名稱,section的起始和偏移等等,通過readelf -S filename 可以查看section header 內(nèi)容。一個可執(zhí)行文件通常由不同的section組成,這里section不能理解成段這個含義,具體解釋看第四小節(jié)。
其結(jié)構(gòu)體如下:

typedef struct {Elf32_Word sh_name; /* Section name (string tbl index) */Elf32_Word sh_type; /* Section type */Elf32_Word sh_flags; /* Section flags */Elf32_Addr sh_addr; /* Section virtual addr at execution */Elf32_Off sh_offset; /* Section file offset */Elf32_Word sh_size; /* Section size in bytes */Elf32_Word sh_link; /* Link to another section */Elf32_Word sh_info; /* Additional section information */Elf32_Word sh_addralign; /* Section alignment */Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr;

下面我們依次講解結(jié)構(gòu)體各個字段,有些字段目前也不理解,后續(xù)慢慢了解吧。

字段描述
sh_name是一個索引值
sh_type描述了section的類型
sh_flags包含位標(biāo)志
sh_addr如果section會出現(xiàn)在進(jìn)程的內(nèi)存映像中,給出了section第一字節(jié)的虛擬地址。
sh_offsetsection相對于文件頭的字節(jié)偏移。對于不占文件空間的section(比如SHT_NOBITS),它的sh_offset只是給出了section邏輯上的位置。
sh_sizesection占多少字節(jié)
sh_link含有一個section header的index,該值的解釋依賴于section type
sh_info存放額外的信息,值的解釋依賴于section type。
sh_addralign地址對齊,如果一個section有一個doubleword字段,系統(tǒng)在載入section時的內(nèi)存地址必須是doubleword對齊。也就是說sh_addr必須是sh_addralign的整數(shù)倍。只有2的正整數(shù)冪是有效的。0和1說明沒有對齊約束。
sh_entsize有些section包含固定大小的記錄,比如符號表。這個值給出了每個記錄大小。對于不包含固定大小記錄的section,這個值是0
sh_type,常見的取值如下:SHT_NULL 0,表明section header無效,沒有關(guān)聯(lián)的section。 SHT_PROGBITS 1,section包含了程序需要的數(shù)據(jù),格式和含義由程序解釋。 SHT_SYMTAB 2, 包含了一個符號表。當(dāng)前,一個ELF文件中只有一個符號表。SHT_SYMTAB提供了用于(link editor)鏈接編輯的符號,當(dāng)然這些符號也可能用于動態(tài)鏈接。這是一個完全的符號表,它包含許多符號。 SHT_STRTAB 3,包含一個字符串表。一個對象文件包含多個字符串表,比如.strtab(包含符號的名字)和.shstrtab(包含section的名稱)。 SHT_RELA 4,重定位節(jié),包含relocation入口,參見Elf32_Rela。一個文件可能有多個Relocation Section。比如.rela.text,.rela.dyn。 SHT_HASH 5,這樣的section包含一個符號hash表,參與動態(tài)連接的目標(biāo)代碼文件必須有一個hash表。目前一個ELF文件中只包含一個hash表。講鏈接的時候再細(xì)講。 SHT_DYNAMIC 6,包含動態(tài)鏈接的信息。目前一個ELF文件只有一個DYNAMIC section。 SHT_NOTE 7,note section, 以某種方式標(biāo)記文件的信息,以后細(xì)講。 SHT_NOBITS 8,這種section不含字節(jié),也不占用文件空間,section header中的sh_offset字段只是概念上的偏移。 SHT_REL 9, 重定位節(jié),包含重定位條目。和SHT_RELA基本相同,兩者的區(qū)別在后面講重定位的時候再細(xì)講。 SHT_SHLIB 10,保留,語義未指定,包含這種類型的section的elf文件不符合ABI。 SHT_DYNSYM 11, 用于動態(tài)連接的符號表,推測是symbol table的子集。 sh_flags, 常用的有:SHF_WRITE 0x1,進(jìn)程執(zhí)行的時候,section內(nèi)的數(shù)據(jù)可寫。 SHF_ALLOC 0x2,進(jìn)程執(zhí)行的時候,section需要占據(jù)內(nèi)存。 SHF_EXECINSTR 0x4,節(jié)內(nèi)包含可以執(zhí)行的機(jī)器指令。 SHF_STRINGS 0x20,包含0結(jié)尾的字符串。 SHF_MASKOS 0x0ff00000,這個mask為OS特定的語義保留8位。 SHF_MASKPROC 0xf0000000,這個mask包含的所有位保留(也就是最高字節(jié)的高4位),為處理器相關(guān)的語義使用。

3.sections

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

系統(tǒng)預(yù)定義了一些節(jié)名(以.開頭),這些節(jié)有其特定的類型和含義。1. .bss:包含程序運行時未初始化的數(shù)據(jù)(全局變量和靜態(tài)變量)。當(dāng)程序運行時,這些數(shù)據(jù)初始化為0。 其類型為SHT_NOBITS,表示不占文件空間。SHF_ALLOC + SHF_WRITE,運行時要占用內(nèi)存的。 2. .comment 包含版本控制信息(是否包含程序的注釋信息?不包含,注釋在預(yù)處理時已經(jīng)被刪除了)。類型為SHT_PROGBITS。 3. .data和.data1,包含初始化的全局變量和靜態(tài)變量。 類型為SHT_PROGBITS,標(biāo)志為SHF_ALLOC + SHF_WRITE(占用內(nèi)存,可寫)。 4. .debug,包含了符號調(diào)試用的信息,我們要想用gdb等工具調(diào)試程序,需要該類型信息,類型為SHT_PROGBITS。 5. .dynamic,類型SHT_DYNAMIC,包含了動態(tài)鏈接的信息。標(biāo)志SHF_ALLOC,是否包含SHF_WRITE和處理器有關(guān)。 6. .dynstr,SHT_STRTAB,包含了動態(tài)鏈接用的字符串,通常是和符號表中的符號關(guān)聯(lián)的字符串。標(biāo)志 SHF_ALLOC 7. .dynsym,類型SHT_DYNSYM,包含動態(tài)鏈接符號表, 標(biāo)志SHF_ALLOC。 8. .fini,類型SHT_PROGBITS,程序正常結(jié)束時,要執(zhí)行該section中的指令。標(biāo)志SHF_ALLOC + SHF_EXECINSTR(占用內(nèi)存可執(zhí)行)。現(xiàn)在ELF還包含.fini_array section。 9. .text: 已編譯程序的二進(jìn)制代碼 10. .hash,類型SHT_HASH,包含符號hash表,以后細(xì)講。標(biāo)志SHF_ALLOC。 11. .init,SHT_PROGBITS,程序運行時,先執(zhí)行該節(jié)中的代碼。SHF_ALLOC + SHF_EXECINSTR,和.fini對應(yīng)。現(xiàn)在ELF還包含.init_array section。 12. .interp,SHT_PROGBITS,該節(jié)內(nèi)容是一個字符串,指定了程序解釋器的路徑名。如果文件中有一個可加載的segment包含該節(jié),屬性就包含SHF_ALLOC,否則不包含。 13. .line,SHT_PROGBITS,包含符號調(diào)試的行號信息,描述了源程序和機(jī)器代碼的對應(yīng)關(guān)系。gdb等調(diào)試器需要此信息。 14. .note Note Section, 類型SHT_NOTE,以后單獨講。 15. .plt 過程鏈接表(Procedure Linkage Table),類型SHT_PROGBITS,以后重點講。 16. .relNAME,類型SHT_REL, 包含重定位信息。如果文件有一個可加載的segment包含該section,section屬性將包含SHF_ALLOC,否則不包含。NAME,是應(yīng)用重定位的節(jié)的名字,比如.text的重定位信息存儲在.rel.text中。 17. .relaname 類型SHT_RELA,和.rel相同。SHT_RELA和SHT_REL的區(qū)別,會在講重定位的時候說明。 18. .rodata和.rodata1。類型SHT_PROGBITS, 包含只讀數(shù)據(jù),組成不可寫的段。標(biāo)志SHF_ALLOC。 .shstrtab,類型SHT_STRTAB,包含section的名字。有讀者可能會問:section header中不是已經(jīng)包含名字了嗎,為什么把名字集中存放在這里? sh_name 包含的是.shstrtab 中的索引,真正的字符串存儲在.shstrtab中。那么section names為什么要集中存儲?我想是這樣:如果有相同的字符串,就可以共用一塊存儲空間。如果字符串存在包含關(guān)系,也可以共用一塊存儲空間。 19. .strtab SHT_STRTAB,包含字符串,通常是符號表中符號對應(yīng)的變量名字。如果文件有一個可加載的segment包含該section,屬性將包含SHF_ALLOC。字符串以\0結(jié)束, section以\0開始,也以\0結(jié)束。一個.strtab可以是空的,它的sh_size將是0。針對空字符串表的非0索引是允許的。 20. symtab,類型SHT_SYMTAB,Symbol Table,符號表。包含了定位、重定位符號定義和引用時需要的信息。符號表是一個數(shù)組,Index 0 第一個入口,它的含義是undefined symbol index, STN_UNDEF。如果文件有一個可加載的segment包含該section,屬性將包含SHF_ALLOC。

4.Program header table

參考文獻(xiàn)

?segment是section的集合,一個segment可以映射到section。

?左邊是ELF的鏈接視圖,可以理解為是目標(biāo)代碼文件的內(nèi)容布局。右邊是ELF的執(zhí)行視圖,可以理解為可執(zhí)行文件的內(nèi)容布局。
?注意目標(biāo)代碼文件的內(nèi)容是由section組成的,而可執(zhí)行文件的內(nèi)容是由segment組成的。
?要注意區(qū)分段(segment)和節(jié)(section)的概念,這兩個概念在后面會經(jīng)常提到。
?我們寫匯編程序時,用.text,.bss,.data這些指示,都指的是section,比如.text,告訴匯編器后面的代碼放入.text section中。
?目標(biāo)代碼文件中的section和section header table中的條目是一一對應(yīng)的。section的信息用于鏈接器對代碼重定位。
?而文件載入內(nèi)存執(zhí)行時,是以segment組織的,每個segment對應(yīng)ELF文件中program header table中的一個條目,用來建立可執(zhí)行文件的進(jìn)程映像。
?比如我們通常說的,代碼段、數(shù)據(jù)段是segment,目標(biāo)代碼中的section會被鏈接器組織到可執(zhí)行文件的各個segment中。
?.text section的內(nèi)容會組裝到代碼段中,.data, .bss等節(jié)的內(nèi)容會包含在數(shù)據(jù)段中。

?可以這么理解。在匯編的時候,也就是.o文件有關(guān)于section的描述,但是沒有segment描述。鏈接器把多個可重定位的目標(biāo)文件中相同的 section 整合成一個segment,成為一個可執(zhí)行文件。在程序運行的時候,方便加載器的加載。


三、實驗驗證

? 1.以如下一個程序sub.c為例:

#include <stdio.h>int add(int a,int b) {return a+b; } int sub(int a,int b) {return a-b;} int goal =10 ; int gobl; int main() {int val,vbl;static int sUao = 20;val =add(4,5);vbl =add(4,3);printf("test :\n");printf("a= [%d],b=[%d]",val,vbl);return 0; } ~

?1.1.將源程序進(jìn)行預(yù)處理、編譯、匯編操作,生成.o文件(可重定位的目標(biāo)文件)。

gcc -c sub.c

?1.2.然后查看ELF header

?可以看出,ELF header 的大小是64字節(jié),每一個section大小64字節(jié),一共有14個,與program 相關(guān)的是0。

? 1.3.接著查看section header.還是符合ELF header 描述的。

readelf -S sub.o //S是大寫的

? 1.4.查看顯示程序頭(段頭)信息,發(fā)現(xiàn)是沒有的,符合ELF header 描述的。

? 2. 將程序編譯成可執(zhí)行文件,可以看見,有了變化,這里把一些文件鏈接了,如glibc庫。

?依次執(zhí)行,查看section header,比之前多了好多。

?再看查看顯示程序頭(段頭)信息,后面就會把各個文件的同屬性節(jié)整合到一塊。

Elf file type is DYN (Shared object file) Entry point 0x1080 There are 13 program headers, starting at offset 64Program Headers:Type Offset VirtAddr PhysAddrFileSiz MemSiz Flags AlignPHDR 0x0000000000000040 0x0000000000000040 0x00000000000000400x00000000000002d8 0x00000000000002d8 R 0x8INTERP 0x0000000000000318 0x0000000000000318 0x00000000000003180x000000000000001c 0x000000000000001c R 0x1[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]LOAD 0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000638 0x0000000000000638 R 0x1000LOAD 0x0000000000001000 0x0000000000001000 0x00000000000010000x0000000000000285 0x0000000000000285 R E 0x1000LOAD 0x0000000000002000 0x0000000000002000 0x00000000000020000x00000000000001b8 0x00000000000001b8 R 0x1000LOAD 0x0000000000002db0 0x0000000000003db0 0x0000000000003db00x0000000000000268 0x0000000000000270 RW 0x1000DYNAMIC 0x0000000000002dc0 0x0000000000003dc0 0x0000000000003dc00x00000000000001f0 0x00000000000001f0 RW 0x8NOTE 0x0000000000000338 0x0000000000000338 0x00000000000003380x0000000000000020 0x0000000000000020 R 0x8NOTE 0x0000000000000358 0x0000000000000358 0x00000000000003580x0000000000000044 0x0000000000000044 R 0x4GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x00000000000003380x0000000000000020 0x0000000000000020 R 0x8GNU_EH_FRAME 0x000000000000201c 0x000000000000201c 0x000000000000201c0x0000000000000054 0x0000000000000054 R 0x4GNU_STACK 0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 RW 0x10GNU_RELRO 0x0000000000002db0 0x0000000000003db0 0x0000000000003db00x0000000000000250 0x0000000000000250 R 0x1Section to Segment mapping:Segment Sections...00 01 .interp 02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 03 .init .plt .plt.got .plt.sec .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .dynamic .got .data .bss 06 .dynamic 07 .note.gnu.property 08 .note.gnu.build-id .note.ABI-tag 09 .note.gnu.property 10 .eh_frame_hdr 11 12 .init_array .fini_array .dynamic .got

readelf 命令介紹鏈接

四、其他

1、符號表和重定位表

? 首先,在程序的匯編中,是通過匯編器將前面所生成的匯編文件搞成目標(biāo)文件。在匯編這一過程中,就生成了符號表和重定位表,這兩個表為后面的鏈接提供了必要的信息。
? 符號表

主要用來保存源程序中各個符號的信息,如符號的地址,類型,占用空間的大小 。

可以通過readelf -s xxx.o 查看。
? 重定位表

如果在當(dāng)前文件中沒有找到符號的定義,會將這些符號搜集到一塊并保存到一個單獨的符號表中,后面在補(bǔ)充,這個符號表就叫重定位符號表。
可以用 readelf -r xxx.o 查看。.rel.text

2、鏈接

?在鏈接階段,有個分段組裝,意思是將各個目標(biāo)文件的代碼段放在一塊,作為最終的代碼段,將各個目標(biāo)文件的數(shù)據(jù)段放在一塊,作為最終的可執(zhí)行文件的數(shù)據(jù)段等等。
與重定向文件一樣,可執(zhí)行文件也會符號表,他是全局的,收集這各個目標(biāo)文件的符號表中的符號.

重定位新地址 = 新的段地址 + 段內(nèi)偏移

總結(jié)

文本主要是淺淺了解了目前用的程序的文件格式。以及編譯的大概流程,對理解程序的運行還是由幫助的,如果還想仔細(xì)去了解,估計的花時間了。

總結(jié)

以上是生活随笔為你收集整理的ELF文件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。