ELF文件格式简介
??簡單了解下ELF文件的格式。
1 簡介
??可執行與可鏈接格式 (Executable and Linkable Format,ELF),常被稱為 ELF格式,是一種用于可執行文件、目標代碼、共享庫和核心轉儲(core dump)的標準文件格式,一般用于類Unix系統,比如Linux,Macox等。ELF 格式靈活性高、可擴展,并且跨平臺。比如它支持不同的字節序和地址范圍,所以它不會不兼容某一特別的 CPU 或指令架構。這也使得 ELF 格式能夠被運行于眾多不同平臺的各種操作系統所廣泛采納。
??ELF文件一般由三種類型的文件:
- 可重定向文件:文件保存著代碼和適當的數據,用來和其他的目標文件一起來創建一個可執行文件或者是一個共享目標文件。比如編譯的中間產物.o文件;
- 可執行文件:一個可執行文件;
- 共享目標文件:共享庫。文件保存著代碼和合適的數據,用來被下連接編輯器和動態鏈接器鏈接。比如linux下的.so文件。
2 ELF文件格式
??在編譯過程中ELF文件格式在鏈接和程序的運行階段的格式不同。鏈接階段每個.o文件都是一個獨立的ELF文件,為了效率和便利性他們的段需要進行合并才能生成對應的可執行文件。
??ELF文件包含一個Header描述文件的基本信息;程序頭表告訴徐彤如何構建進程的內存鏡像,因此只有可執行文件由程序頭表;Sections描述了鏈接過程中的需要的符號表、數據、指令等信息,而在可執行文件中是Segments,是經過合并的Secitons;節/段頭表指明了對應section/segment在文件中的偏移,鏈接階段的ELF文件必須包含該表頭;而每個節/段頭描述了對應的section/segment的大小,入口等基本信息。
??下圖是32bit系統下面使用的字段的數大小,64bit系統類似,之后不在贅述。
2.1 ELF Header
??ELF文件頭描述了ELF文件的基本類型,地址偏移等信息,分為32bit和64bit兩個版本,定義于linux源碼的/usr/include/elf.h文件中。
#define EI_NIDENT 16typedef struct elf32_hdr{unsigned char e_ident[EI_NIDENT];Elf32_Half e_type;Elf32_Half e_machine;Elf32_Word e_version;Elf32_Addr e_entry; /* Entry point */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; typedef struct elf64_hdr {unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */Elf64_Half e_type;Elf64_Half e_machine;Elf64_Word e_version;Elf64_Addr e_entry; /* Entry point virtual address */Elf64_Off e_phoff; /* Program header table file offset */Elf64_Off e_shoff; /* Section header table file offset */Elf64_Word e_flags;Elf64_Half e_ehsize;Elf64_Half e_phentsize;Elf64_Half e_phnum;Elf64_Half e_shentsize;Elf64_Half e_shnum;Elf64_Half e_shstrndx; } Elf64_Ehdr;??從上面的結構中能夠看出32bit和64bit的區別僅僅是字長的區別,字段上沒有實際上的差別。每個字段的含義如下:
- e_ident:ELF文件的描述,是一個16字節的標識,表明當前文件的數據格式,位數等:
- [0,3]字節為魔數,即e_ident[EI_MAG0-EI_MAG3],取值為固定的0x7f E L F,標記當前文件為一個ELF文件;
- [4,4]字節為EI_CLASS即e_ident[EI_CLASS],表明當前文件的類別:
- 0:表示非法的類別;
- 1:表示32bit;
- 2:表示64bit;
- [5,5]字節為EI_DATA即e_ident[EI_DATA],表明當期那文件的數據排列方式:
- 0表示非法;
- 1表示小端;
- 2表示大端;
- [6,6]字節為EI_VERSION即e_ident[EI_VERSION],表明當前文件的版本,目前該取值必須為EV_CURRENT即1;
- [7,7]字節為EI_PAD即e_ident[EI_PAD]表明e_ident中未使用的字節的起點(值是相對于e_ident[EI_PAD+1]的偏移),未使用的字節會被初始化為0,解析ELF文件時需要忽略對應的字段;
??EI_MAG0,EI_MAG1,EI_MAG2,EI_MAG3,EI_CLASS,EI_DATA,EI_VERSION,EI_OSABI,EI_PAD是linux源碼中定義的宏,取值分別為0-7,分別對應各個字段的下標;下面的宏定義將采用類似EI_MAG0(0)的方式,表示EI_MAG0的值為0。
- e_type:文件的標識字段標識文件的類型;
- ET_NONE(0):未知的文件格式;
- ET_REL(1):可重定位文件,比如目標文件;
- ET_EXEC(2):可執行文件;
- ET_DYN(3):共享目標文件;
- ET_CORE(4):Core轉儲文件,比如程序crash之后的轉儲文件;
- ET_LOPROC(0xff00):特定處理器的文件標識;
- ET_HIPROC(0xffff):特定處理器的文件標識;
- [ET_LOPROC,ET_HIPROC]之間的值用來表示特定處理器的文件格式;
- e_machine:目標文件的體系結構(下面列舉了少數處理器架構,具體ELF文件支持的架構在對應的文件中查看即可);
- ET_NONE(0):未知的處理器架構;
- EM_M32(1):AT&T WE 32100;
- EM_SPARC(2):SPARC;
- EM_386(3):Intel 80386;
- EM_68K(4):Motorola 68000;
- EM_88K(5):Motorola 88000;
- EM_860(6):Intel 80860;
- EM_MIPS(7):MIPS RS3000大端;
- EM_MIPS_RS4_BE(10):MIPS RS4000大端;
- 其他,預留;
- e_version:當前文件的版本;
- EV_NONE(0):非法的版本;
- EV_CURRENT(`):當前版本;
- e_entry:程序的虛擬入口地址,如果文件沒有對應的入口可以為0;
- e_phoff:文件中程序頭表的偏移(bytes),如果文件沒有該項,則應該為0;
- e_shoff:文件中段表/節表的偏移(bytes),如果文件沒有該項,則應該為0;
- e_flags:處理器相關的標志位,宏格式為EF_machine_flag比如EF_MIPS_PIC;
- e_ehsize:ELF文件頭的大小(bytes);
- e_phentsize:程序頭表中單項的大小,表中每一項的大小相同;
- e_phnum:程序頭表中的項數,也就是說程序頭表的實際大小為ephentsize x e_phnum,如果文件中沒有程序頭表該項為0;
- e_shentsize:節表中單項的大小,表中每一項的大小相同;
- e_shnum:節表中項的數量;
- e_shstrndx:節表中節名的索引,如果文件沒有該表則該項為SHN_UNDEF(0)。
2.2 程序頭表(Program Header Table)
??可執行文件或者共享目標文件的程序頭部是一個結構數組,每個結構描述了一個段 或者系統準備程序執行所必需的其它信息。程序頭表描述了ELF文件中Segment在文件中的布局,描述了OS該如何裝載可執行文件到內存。程序頭表的表項的描述如下,類似于ELF Header也有32和64位兩個版本。
typedef struct elf32_phdr {Elf32_Word p_type;Elf32_Off p_offset;Elf32_Addr p_vaddr;Elf32_Addr p_paddr;Elf32_Word p_filesz;Elf32_Word p_memsz;Elf32_Word p_flags;Elf32_Word p_align; } Elf32_Phdr; typedef struct elf64_phdr {Elf64_Word p_type;Elf64_Word p_flags;Elf64_Off p_offset; /* Segment file offset */Elf64_Addr p_vaddr; /* Segment virtual address */Elf64_Addr p_paddr; /* Segment physical address */Elf64_Xword p_filesz; /* Segment size in file */Elf64_Xword p_memsz; /* Segment size in memory */Elf64_Xword p_align; /* Segment alignment, file & memory */ } Elf64_Phdr;- p_type:當前Segment的類型;
- PT_NULL(0):當前項未使用,項中的成員是未定義的,需要忽略當前項;
- PT_LOAD(1):當前Segment是一個可裝載的Segment,即可以被裝載映射到內存中,其大小由p_filesz和p_memsz描述。如果p_memsz>p_filesz則剩余的字節被置零,但是p_filesz>p_memsz是非法的。動態庫一般包含兩個該類型的段:代碼段和數據段;
- PT_DYNAMIC(2):動態段,動態庫特有的段,包含了動態鏈接必須的一些信息,比如需要鏈接的共享庫列表、GOT等等;
- PT_INTERP(3):當前段用于存儲一段以NULL為結尾的字符串,該字符串表明了程序解釋器的位置。且當前段僅僅對于可執行文件有實際意義,一個可執行文件中不能出現兩個當前段,如果一個文件中包含當前段。比如/lib64/ld-linux-x86-64.so.2;
- PT_NOTE(4):用于保存與特定供應商或者系統相關的附加信息以便于兼容性、一致性檢查,但是實際上只保存了操作系統的規范信息;
- PT_SHLIB(5):保留段;
- PT_PHDR(6):保存程序頭表本身的位置和大小,當前段不能在文件中出現一次以上,且僅僅當程序表頭為內存映像的一部分時起作用,它必須在所有加載項目之前;
- [PT_LPROC(0x70000000),PT_HIPROC(0x7fffffff)]:該范圍內的值用作預留;
- p_offset:當前段相對于文件起始位置的偏移量;
- p_vaddr:段的第一個字節將被映射到到內存中的虛擬地址;
- p_paddr:此成員僅用于與物理地址相關的系統中。因為 System V 忽略所有應用程序的物理地址信息,此字段對與可執行文件和共享目標文件而言具體內容是指定的;
- p_filesz:段在文件映像中所占的字節數,可能為 0;
- p_memsz:段在內存映像中占用的字節數,可能為 0;
- p_flags:段相關的標志;
- p_align:段在文件中和內存中如何對齊。可加載的進程段的p_vaddr和- p_offset取值必須合適,相對于對頁面大小的取模而言;
- 0和1表示不需要對齊;
- 其他值必須為2的冪次方,且必須p_addr∣p_align==p_offset∣palignp\_addr|p\_align==p\_offset| p_alignp_addr∣p_align==p_offset∣pa?lign。
2.3 節頭表(Section Header Table)
??節頭表描述了ELF文件中的節的基本信息。可執行文件不一定由節頭表但是一定有節,節頭表可利用特殊的方式去除。
??段和節的區別是:
- 段包含了程序裝載可執行的基本信息,段告訴OS如何裝載當前段到虛擬內存以及當前段的權限等和執行相關的信息,一個段可以包含0個或多個節;
- 節包含了程序的代碼和數據等內容,鏈接器會將多個節合并為一個段。
- sh_name:值是節名稱在字符串表中的索引;
- sh_type:描述節的類型和語義;
- SHT_NULL(0):當前節是非活躍的,沒有一個對應的具體的節內存;
- SHT_PROGBITS(1):包含了程序的指令信息、數據等程序運行相關的信息;
- SHT_SYMTAB(2):保存了符號信息,用于重定位;
- 此種類型節的sh_link存儲相關字符串表的節索引,sh_info存儲最后一個局部符號的符號表索引+1;
- SHT_DYNSYM(11):保存共享庫導入動態符號信息;
- 此種類型節的sh_link存儲相關字符串表的節索引,sh_info存儲最后一個局部符號的符號表索引+1;
- SHT_STRTAB(3):一個字符串表,保存了每個節的節名稱;
- SHT_RELA(4):存儲可重定位表項,可能會有附加內容,目標文件可能有多個可重定位表項;
- 此種類型節的sh_link存儲相關符號表的節索引,sh_info存儲重定位所使用節的索引;
- SHT_HASH(5):存儲符號哈希表,所有參與動態鏈接的目標只能包含一個哈希表,一個目標文件只能包含一個哈希表;
- 此種類型節的sh_link存儲哈希表所使用的符號表的節索引,sh_info為0;
- SHT_DYAMIC(6):存儲包含動態鏈接的信息,一個目標文件只能包含一個;
- 此種類型的節的sh_link存儲當前節中使用到的字符串表格的節的索引,sh_info為0;
- SHT_NOTE(7):存儲以某種形式標記文件的信息;
- SHT_NOBITS(8):這種類型的節不占據文件空間,但是成員sh_offset依然會包含對應的偏移;
- SHT_REL(9):包含可重定位表項,無附加內容,目標文件可能有多個可重定位表項;
- 此種類型節的sh_link存儲相關符號表的節索引,sh_info存儲重定位所使用節的索引;
- SHT_SHLIB(10):保留區,包含此節的程序與ABI不兼容;
- [SHT_LOPROC(0x70000000),SHT_HIPROC(0x7fffffff)]:留給處理器專用語義;
- [SHT_LOUSER(0x80000000),SHT_HIUSER(0xffffffff)]:預留;
- sh_flags:1bit位的標志位;
- SHF_WRITE(0x1):當前節包含進程執行過程中可寫的數據;
- SHF_ALLOC(0x2):當前節在運行階段占據內存;
- SHF_EXECINSTR(0x4):當前節包含可執行的機器指令;
- SHF_MASKPROC(0xf0000000):所有包含當前掩碼都表示預留給特定處理器的;
- sh_addr:如果當前節需要被裝載到內存,則當前項存儲當前節映射到內存的首地址,否則應該為0;
- sh_offset:當前節的首地址相對于文件的偏移;
- sh_size:節的大小。但是對于類型為SHT_NOBITS的節,當前值可能不為0但是在文件中不占據任何空間;
- sh_link:存儲節投標中的索引,表示當前節依賴于對應的節。對于特定的節有特定的含義,其他為SHN_UNDEF;
- sh_info:節的附加信息。對于特定的節有特定的含義,其他為0;
- sh_addralign:地址約束對齊,值應該為0或者2的冪次方,0和1表示未進行對齊;
- sh_entsize:某些節是一個數組,對于這類節當前字段給出數組中每個項的字節數,比如符號表。如果節并不包含對應的數組,值應該為0。
2.3 一些特殊的節
??ELF文件中有一些預定義的節來保存程序、數據和一些控制信息,這些節被用來鏈接或者裝載程序。每個操作系統都支持一組鏈接模式,主要分為兩類(也就是常說的動態庫和靜態庫):
- Static:靜態綁定的一組目標文件、系統庫和庫檔案(比如靜態庫),解析包含的符號引用并創建一個完全自包含的可執行文件;
- Dynamic:一組目標文件、庫、系統共享資源和其他共享庫鏈接在一起創建可執行文件。當加載此可執行文件時必須使系統中其他共享資源和動態庫可用,程序才能正常運行。
??庫文件無論是動態庫還是靜態庫在其文件中都包含對應的節,一些特殊的節其功能如下:
- .bss,類型SHT_NOBITS,屬性SHF_ALLOC|SHF_WRITE:存儲未經初始化的數據。根據定義程序開始執行時,系統會將這些數據初始化為0,且此節不占用文件空間;
- .comment,類型SHT_PROGBITS,屬性none:存儲版本控制信息;
- .data,類型SHT_PROGBITS,屬性SHF_ALLOC|SHF_WRITE:存放初始化的數據;
- .data1,類型SHT_PROGBITS,屬性SHF_ALLOC|SHF_WRITE:存放初始化的數據;
- .debug,類型SHT_PROGBITS,屬性none:存放用于符號調試的信息;
- .dynamic,類型SHT_DYNAMIC,屬性SHF_ALLOC,是否有屬性SHF_WRITE屈居于處理器:包含動態鏈接的信息,
- .hash,類型SHT_HASH,屬性SHF_ALLOC:
- .line,類型SHT_PROGBITS,屬性none:存儲調試的行號信息,描述源代碼和機器碼之間的對應關系;
- .note,類型SHT_NOTE,屬性none:
- .rodata,類型SHT_PROGBITS,屬性SHF_ALLOC:存儲只讀數據;
- .rodata1,類型SHT_PROGBITS,屬性SHF_ALLOC:存儲只讀數據;
- .shstrtab,類型SHT_STRTAB,屬性none:存儲節的名稱;
- .strtab,類型SHT_STRTAB:存儲常見的與符號表關聯的字符串。如果文件有一個包含符號字符串表的可加載段,則該段的屬性將包括 SHF_ALLOC 位; 否則,該位將關閉;
- .symtab,類型SHT_SYMTAB,屬性``````:存儲一個符號表。如果文件具有包含符號表的可加載段,則該節的屬性將包括 SHF_ALLOC 位;否則,該位將關閉;
- .text,類型SHT_PROGBITS,屬性SHF_ALLOC|SHF_EXECINSTR:存儲程序的代碼指令;
- .dynstr,類型SHT_STRTAB,屬性SHF_ALLOC:存儲動態鏈接所需的字符串,最常見的是表示與符號表條目關聯的名稱的字符串;
- .dynsym,類型SHT_DYNSYM,屬性SHF_ALLOC:存儲動態鏈接符號表;
- .fini,類型SHT_PROGBITS,屬性SHF_ALLOC|SHF_EXECINSTR:存儲有助于進程終止代碼的可執行指令。 當程序正常退出時,系統執行本節代碼;
- .init,類型SHT_PROGBITS,屬性SHF_ALLOC|SHF_EXECINSTR:存儲有助于進程初始化代碼的可執行指令。 當程序開始運行時,系統會在調用主程序入口點(C 程序稱為 main)之前執行本節中的代碼;
- .interp,類型SHT_PROGBITS:保存程序解釋器的路徑名。 如果文件有一個包含該節的可加載段,則該節的屬性將包括 SHF_ALLOC 位; 否則,該位將關閉;
- .relname,類型SHT_REL:包含重定位信息。如果文件具有包含重定位的可加載段,則這些部分的屬性將包括 SHF_ALLOC 位;否則,該位將關閉。通常,名稱由 重定位適用的部分。因此.text的重定位部分通常具有名稱.rel.text或.rela.text;
- .relaname,類型SHT_RELA:同relname。
- 其他:對于C++程序有些版本會有.ctors(有時也會是.init_array,見Can’t find .dtors and .ctors in binary)和dtors兩個節存儲構造和析構相關的代碼。
??帶有點 (.) 前綴的部分名稱是為系統保留的,但如果它們的現有含義令人滿意,應用程序可以使用這些部分。 應用程序可以使用不帶前綴的名稱以避免與系統部分沖突。 目標文件格式允許定義不在上面列表中的部分。 一個目標文件可能有多個同名的部分。
2.4 字符串表
??字符串表是一個存儲字符串的表格,而每個字符串是以NULL也就是\0為結尾的。字符串表格中索引為0處的字符串被定義為空字符串。符號表中保存的字符串是節名和目標文件中使用到的符號。而需要使用對應字符串時,只需要在需要使用的地方指明對應字符在字符串表中的索引即可,使用的字符串就是索引處到第一個\0之間的字符串。
2.5 符號表
??目標文件的符號表包含定位和重定位程序的符號定義和引用所需的信息。符號表索引是該數組的下標。索引0既指定表中的第一個條目,又用作未定義的符號索引。
typedef struct elf32_sym{Elf32_Word st_name;Elf32_Addr st_value;Elf32_Word st_size;unsigned char st_info;unsigned char st_other;Elf32_Half st_shndx; } Elf32_Sym; typedef struct elf64_sym {Elf64_Word st_name; /* Symbol name, index in string tbl */unsigned char st_info; /* Type and binding attributes */unsigned char st_other; /* No defined meaning, 0 */Elf64_Half st_shndx; /* Associated section index */Elf64_Addr st_value; /* Value of the symbol */Elf64_Xword st_size; /* Associated symbol size */ } Elf64_Sym;- st_name:存儲一個指向字符串表的索引來表示對應符號的名稱;
- st_value:存儲對應符號的取值,具體值依賴于上下文,可能是一個指針地址,立即數等。另外,不同對象文件類型的符號表條目對 st_value 成員的解釋略有不同:
- 在重定位文件中在可重定位文件中,st_value保存節索引為SHN_COMMON的符號的對齊約束;
- 在可重定位文件中,st_value保存已定義符號的節偏移量。 也就是說,st_value是從st_shndx標識的部分的開頭的偏移量;
- 在可執行文件和共享對象文件中,st_value保存一個虛擬地址。 為了使這些文件的符號對動態鏈接器更有用,節偏移(文件解釋)讓位于與節號無關的虛擬地址(內存解釋)。
- st_size:符號的大小,具體指為sizeof(instance),如果未知則為0;
- st_info:指定符號的類型和綁定屬性。可以用下面的代碼分別解析出bind,type,info三個屬性:
- BIND
- STB_LOCAL(0):局部符號在包含其定義的目標文件之外是不可見的。 同名的本地符號可以存在于多個文件中,互不干擾;
- STB_GLOBAL(1):全局符號對所有正在組合的目標文件都是可見的。 一個文件對全局符號的定義將滿足另一個文件對同一全局符號的未定義引用;
- STB_WEAK(2):弱符號類似于全局符號,但它們的定義具有較低的優先級;
- [STB_LOPROC(13),STB_HIPROC(15)]:預留位,用于特殊處理器的特定含義;
- TYPE:
- STT_NOTYPE(0):符號的類型未指定;
- STT_OBJECT(1):符號與數據對象相關聯,例如變量、數組等;
- STT_FUNC(2):符號與函數或其他可執行代碼相關聯;
- STT_SECTION(3):該符號與一個節相關聯。 這種類型的符號表條目主要用于重定位,通常具有STB_LOCALBIND屬性;
- STT_FILE(4):一個有STB_LOCAL的BIND屬性的文件符號的節索引為SHN_ABS。并且如果存在其他STB_LOCAL屬性的符號,則當前符號應該在其之前;
- [STT_LOPROC(13),STT_HIPROC(15)]:預留位,用于特殊處理器的特定含義;
- INFO:
- SHN_ABS:符號有一個絕對值,不會因為重定位而改變;
- SHN_COMMON:該符號標記尚未分配的公共塊。 符號的值給出了對齊約束,類似于節的 sh_addralign 成員。 也就是說,鏈接編輯器將為符號分配存儲空間,該地址是 st_value 的倍數。 符號的大小表明需要多少字節;
- SHN_UNDEF:此節表索引表示該符號未定義。 當鏈接編輯器將此對象文件與另一個定義指定符號的文件組合時,此文件對符號的引用將鏈接到實際定義;
- st_other:該成員當前持有 0 并且沒有定義的含義;
- st_shndx:每個符號都有屬于的節,當前成員存儲的就是對應節的索引。
3 ELF文件示例
??下面是使用下面的代碼編譯生成動態庫libadd.so作為示例:
//add.h int add(int a, int b); static int mult(int a, int b); //add.c //編譯命令gcc add.c -shared -o libadd.so extern int extern_value; static int static_value = 1; static int static_value1;int add(int a, int b){return 0; }static int mult(int a, int b){return 1; }3.1 ELF Header
??使用命令readelf -h <ELF文件名>查看ELF文件的Header。
//readelf -h libadd.so ELF Header:Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00Class: ELF64Data: 2's complement, little endianVersion: 1 (current)OS/ABI: UNIX - System VABI Version: 0Type: DYN (Shared object file)Machine: Advanced Micro Devices X86-64Version: 0x1Entry point address: 0x4a0Start of program headers: 64 (bytes into file)Start of section headers: 6000 (bytes into file)Flags: 0x0Size of this header: 64 (bytes)Size of program headers: 56 (bytes)Number of program headers: 7Size of section headers: 64 (bytes)Number of section headers: 24Section header string table index: 23??從上面的Magic Number中能夠看出:當前文件類型為64bit的共享庫,小端存儲,版本為1,機器架構為x86-64,程序頭表項有7項,節頭表項有24項。
3.2 Program Header Table
??使用命令readelf -l <ELF文件名>查看程序頭表;
//readelf -l libadd.so Elf file type is DYN (Shared object file) Entry point 0x4a0 There are 7 program headers, starting at offset 64 Program Headers:Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000674 0x0000000000000674 R E 0x200000LOAD 0x0000000000000e80 0x0000000000200e80 0x0000000000200e80 0x00000000000001a4 0x00000000000001b0 RW 0x200000DYNAMIC 0x0000000000000e90 0x0000000000200e90 0x0000000000200e90 0x0000000000000150 0x0000000000000150 RW 0x8NOTE 0x00000000000001c8 0x00000000000001c8 0x00000000000001c8 0x0000000000000024 0x0000000000000024 R 0x4GNU_EH_FRAME 0x00000000000005a8 0x00000000000005a8 0x00000000000005a8 0x000000000000002c 0x000000000000002c R 0x4GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10GNU_RELRO 0x0000000000000e80 0x0000000000200e80 0x0000000000200e80 0x0000000000000180 0x0000000000000180 R 0x1Section to Segment mapping:Segment Sections...00 .note.gnu.build-id .gnu.hash .dynsym .dynstr .rela.dyn .init .plt .plt.got .text .fini .eh_frame_hdr .eh_frame01 .init_array .fini_array .dynamic .got .got.plt .data .bss02 .dynamic03 .note.gnu.build-id04 .eh_frame_hdr0506 .init_array .fini_array .dynamic .got??從上面看出上半部分的內容基本和程序頭表項的每個字段基本對應。從下面的Segment Sections可以看出一個Segment是多個Section的集合。
3.3 Section Header Table
??使用命令readelf -S <ELF文件名>查看節頭表的內容。
? tmp readelf -S libadd.so There are 24 section headers, starting at offset 0x1770:Section Headers:[Nr] Name Type Address Offset Size EntSize Flags Link Info Align[ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0[ 1] .note.gnu.build-i NOTE 00000000000001c8 000001c8 0000000000000024 0000000000000000 A 0 0 4[ 2] .gnu.hash GNU_HASH 00000000000001f0 000001f0 000000000000003c 0000000000000000 A 3 0 8[ 3] .dynsym DYNSYM 0000000000000230 00000230 0000000000000108 0000000000000018 A 4 1 8[ 4] .dynstr STRTAB 0000000000000338 00000338 000000000000007d 0000000000000000 A 0 0 1[ 5] .rela.dyn RELA 00000000000003b8 000003b8 00000000000000a8 0000000000000018 A 3 0 8[ 6] .init PROGBITS 0000000000000460 00000460 0000000000000017 0000000000000000 AX 0 0 4[ 7] .plt PROGBITS 0000000000000480 00000480 0000000000000010 0000000000000010 AX 0 0 16[ 8] .plt.got PROGBITS 0000000000000490 00000490 0000000000000008 0000000000000008 AX 0 0 8[ 9] .text PROGBITS 00000000000004a0 000004a0 00000000000000fc 0000000000000000 AX 0 0 16[10] .fini PROGBITS 000000000000059c 0000059c 0000000000000009 0000000000000000 AX 0 0 4[11] .eh_frame_hdr PROGBITS 00000000000005a8 000005a8 000000000000002c 0000000000000000 A 0 0 4[12] .eh_frame PROGBITS 00000000000005d8 000005d8 000000000000009c 0000000000000000 A 0 0 8[13] .init_array INIT_ARRAY 0000000000200e80 00000e80 0000000000000008 0000000000000008 WA 0 0 8[14] .fini_array FINI_ARRAY 0000000000200e88 00000e88 0000000000000008 0000000000000008 WA 0 0 8[15] .dynamic DYNAMIC 0000000000200e90 00000e90 0000000000000150 0000000000000010 WA 4 0 8[16] .got PROGBITS 0000000000200fe0 00000fe0 0000000000000020 0000000000000008 WA 0 0 8[17] .got.plt PROGBITS 0000000000201000 00001000 0000000000000018 0000000000000008 WA 0 0 8[18] .data PROGBITS 0000000000201018 00001018 000000000000000c 0000000000000000 WA 0 0 8[19] .bss NOBITS 0000000000201024 00001024 000000000000000c 0000000000000000 WA 0 0 4[20] .comment PROGBITS 0000000000000000 00001024 0000000000000029 0000000000000001 MS 0 0 1[21] .symtab SYMTAB 0000000000000000 00001050 00000000000004c8 0000000000000018 22 41 8[22] .strtab STRTAB 0000000000000000 00001518 0000000000000193 0000000000000000 0 0 1[23] .shstrtab STRTAB 0000000000000000 000016ab 00000000000000c3 0000000000000000 0 0 1 Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), I (info),L (link order), O (extra OS processing required), G (group), T (TLS),C (compressed), x (unknown), o (OS specific), E (exclude),l (large), p (processor specific)??從上面看出內容基本和程序頭表項的每個字段基本對應。除了上面提到的特殊的節也有一些額外的節,比如.got.plt。
3.4 符號表
??readelf -s <ELF文件名>查看符號表。
//readelf -s libadd.so Symbol table '.dynsym' contains 11 entries:Num: Value Size Type Bind Vis Ndx Name0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__5: 0000000000201024 0 NOTYPE GLOBAL DEFAULT 18 _edata6: 0000000000201030 0 NOTYPE GLOBAL DEFAULT 19 _end7: 0000000000000460 0 FUNC GLOBAL DEFAULT 6 _init8: 000000000000057a 17 FUNC GLOBAL DEFAULT 9 add9: 0000000000201024 0 NOTYPE GLOBAL DEFAULT 19 __bss_start10: 000000000000059c 0 FUNC GLOBAL DEFAULT 10 _finiSymbol table '.symtab' contains 51 entries:Num: Value Size Type Bind Vis Ndx Name0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND1: 00000000000001c8 0 SECTION LOCAL DEFAULT 12: 00000000000001f0 0 SECTION LOCAL DEFAULT 23: 0000000000000230 0 SECTION LOCAL DEFAULT 34: 0000000000000338 0 SECTION LOCAL DEFAULT 45: 00000000000003b8 0 SECTION LOCAL DEFAULT 56: 0000000000000460 0 SECTION LOCAL DEFAULT 67: 0000000000000480 0 SECTION LOCAL DEFAULT 78: 0000000000000490 0 SECTION LOCAL DEFAULT 89: 00000000000004a0 0 SECTION LOCAL DEFAULT 910: 000000000000059c 0 SECTION LOCAL DEFAULT 1011: 00000000000005a8 0 SECTION LOCAL DEFAULT 1112: 00000000000005d8 0 SECTION LOCAL DEFAULT 1213: 0000000000200e80 0 SECTION LOCAL DEFAULT 1314: 0000000000200e88 0 SECTION LOCAL DEFAULT 1415: 0000000000200e90 0 SECTION LOCAL DEFAULT 1516: 0000000000200fe0 0 SECTION LOCAL DEFAULT 1617: 0000000000201000 0 SECTION LOCAL DEFAULT 1718: 0000000000201018 0 SECTION LOCAL DEFAULT 1819: 0000000000201024 0 SECTION LOCAL DEFAULT 1920: 0000000000000000 0 SECTION LOCAL DEFAULT 2021: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c22: 00000000000004a0 0 FUNC LOCAL DEFAULT 9 deregister_tm_clones23: 00000000000004e0 0 FUNC LOCAL DEFAULT 9 register_tm_clones24: 0000000000000530 0 FUNC LOCAL DEFAULT 9 __do_global_dtors_aux25: 0000000000201024 1 OBJECT LOCAL DEFAULT 19 completed.769826: 0000000000200e88 0 OBJECT LOCAL DEFAULT 14 __do_global_dtors_aux_fin27: 0000000000000570 0 FUNC LOCAL DEFAULT 9 frame_dummy28: 0000000000200e80 0 OBJECT LOCAL DEFAULT 13 __frame_dummy_init_array_29: 0000000000000000 0 FILE LOCAL DEFAULT ABS add.c30: 0000000000201020 4 OBJECT LOCAL DEFAULT 18 static_value31: 0000000000201028 4 OBJECT LOCAL DEFAULT 19 static_value132: 000000000000058b 17 FUNC LOCAL DEFAULT 9 mult33: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c34: 0000000000000670 0 OBJECT LOCAL DEFAULT 12 __FRAME_END__35: 0000000000000000 0 FILE LOCAL DEFAULT ABS36: 0000000000200e90 0 OBJECT LOCAL DEFAULT 15 _DYNAMIC37: 0000000000201028 0 OBJECT LOCAL DEFAULT 18 __TMC_END__38: 0000000000201018 0 OBJECT LOCAL DEFAULT 18 __dso_handle39: 00000000000005a8 0 NOTYPE LOCAL DEFAULT 11 __GNU_EH_FRAME_HDR40: 0000000000201000 0 OBJECT LOCAL DEFAULT 17 _GLOBAL_OFFSET_TABLE_41: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize42: 0000000000000460 0 FUNC GLOBAL DEFAULT 6 _init43: 000000000000057a 17 FUNC GLOBAL DEFAULT 9 add44: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable45: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab46: 0000000000201024 0 NOTYPE GLOBAL DEFAULT 19 __bss_start47: 000000000000059c 0 FUNC GLOBAL DEFAULT 10 _fini48: 0000000000201024 0 NOTYPE GLOBAL DEFAULT 18 _edata49: 0000000000201030 0 NOTYPE GLOBAL DEFAULT 19 _end50: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__??符號表可以看出有兩個分別為dynsym和symtab,symtab中包含所有在程序中出現的符號以及一些庫函數的符號,而dynsym中的符號是symtab中符號的子集,僅僅出現了外部可以看到的符號(靜態函數mult的符號在dynsym就看不到)。這是因為dynsym中的符號只有在動態鏈接時也就是運行時才能被解析。
4 參考文獻
- Executable and Linkable Format
- Tool Interface Standard (TIS) Executable and Linking Format (ELF)Specification Version 1.2
- What’s the difference of section and segment in ELF file format
- ELF文件格式
總結
- 上一篇: 【java】本地客户端内嵌浏览器1 -
- 下一篇: elf文件结构解析