Linux elf文件分析
目錄
- 前言
- elf文件格式
- 1、大致結(jié)構(gòu)
- 2、ELF header(Ehdr)
- 3、Program Header Table(Phdr)
- 4、section header table(Shdr)
- 查看elf文件信息
前言
elf文件是儲(chǔ)存linux下可重定位文件(.o,.ko),可執(zhí)行文件,共享目標(biāo)文件(.so)的一種文件。
elf文件格式
1、大致結(jié)構(gòu)
2、ELF header(Ehdr)
-
ELF header的定義可以在 /usr/include/elf.h 中找到。Elf32_Ehdr是32位 ELF header的結(jié)構(gòu)體。Elf64_Ehdr是64位ELF header的結(jié)構(gòu)體,兩者主要區(qū)別在于某些成員的長(zhǎng)度不一樣;
-
Ehdr 各個(gè)成員的說(shuō)明
e_ident[**] //elf標(biāo)識(shí) e_type; //elf類(lèi)型(重定位文件rel(.o,.ko),可執(zhí)行文件,共享目標(biāo)文件dyn(.so)) e_ machine; //目標(biāo)文件體系類(lèi)型,即運(yùn)行架構(gòu),如x86、riscv、arm等 e_version; //目標(biāo)文件版本 e_entry; //elf入口地址 e_ phoff; //程序頭部偏移 e_shoff; //節(jié)區(qū)頭部偏移 e_flags; //處理器的特定標(biāo)志,32位和64位Intel架構(gòu)都沒(méi)有定義標(biāo)志,因此eflags的值是0 e_ehsize; //ELF格式頭部大小 e_phentsize; //程序頭部表項(xiàng)大小 e_phnum; //程序頭表項(xiàng)個(gè)數(shù),即segment數(shù)(各個(gè)segment連續(xù)存放) e_shentsize; //節(jié)區(qū)頭部表項(xiàng)大小 e_shnum; //節(jié)區(qū)表項(xiàng)個(gè)數(shù),即section數(shù)(各個(gè)section連續(xù)存放) e_shstrndx; //str節(jié)區(qū)(symbol的名字)在節(jié)區(qū)中位置(inedx)//可以使用命令 readelf 文件名,幫助理解ELF header(Ehdr)
ELF文件解析(二):ELF header詳解 - JollyWing - 博客園 (cnblogs.com)
3、Program Header Table(Phdr)
-
將多個(gè)section 再包一層,各個(gè)成員說(shuō)明
p_type; //segment類(lèi)型,segment就是一些段信息(.text,.rodata..),//一個(gè)segment包含多個(gè)section p_offset; //segment在文件中的偏移 p_vaddr; //segment虛地址 p_paddr; //物理地址 p_filesz; //文件中segment字節(jié)數(shù) p_memsz; //內(nèi)存中segment字節(jié)數(shù) p_flags; p_align;
注意:一般只有可執(zhí)行文件才有(有錯(cuò)請(qǐng)指出)
4、section header table(Shdr)
-
section header結(jié)構(gòu)體的定義可以在 /usr/include/elf.h
-
Shdr 各成員說(shuō)明
sh_name; //一個(gè)索引值,在shstrtable(section header string table,包含section name的字符串表,也是一個(gè)section)中的索引 sh_type; //節(jié)區(qū)種類(lèi),如rel* sh_flags; //可寫(xiě),可分配,可執(zhí)行等屬性 sh_addr; //如果section會(huì)出現(xiàn)在進(jìn)程的內(nèi)存映像中,給出了section第一字節(jié)的虛擬地址;Relocatable file 的虛存地址都為0。Executable file 和 Shared object file 才會(huì)為有需要的 Section 計(jì)算虛存地址 sh_offset; //給出節(jié)區(qū)第一個(gè)字節(jié)在elf文件中的偏移 sh_size; //節(jié)區(qū)大小 sh_link; //給出字節(jié)頭部表索引鏈接 sh_info; //給出節(jié)區(qū)附加信息 sh_addralign; //地址對(duì)齊約束 sh_entsize; //給出對(duì)于某些有固定項(xiàng)目的大小,如符號(hào)表,這個(gè)值給出了每個(gè)記錄大小。//一個(gè)可執(zhí)行文件中包含多個(gè)section段(對(duì)應(yīng)源文件中使用section定義的段,鏈接腳本會(huì)定義哪些段為代碼),一個(gè)section中有可能有多個(gè)函數(shù)(多段代碼使用一個(gè)section定義) //可以使用命令 objdump -s -d 文件名,查看文件的的section信息,幫助理解 -
.symtab(符號(hào)表,section的一種),符號(hào)表中每個(gè)entry 的結(jié)構(gòu)如下:
st_name; //一個(gè)索引值,在shstrtable(section header string table,包含section name的字符串表,也是一個(gè)section)中的索引 st_value; //可重定向文件(.ko):相對(duì)于節(jié)起始地址的偏移。//可執(zhí)行文件(vmlinux):絕對(duì)地址。 st_size; //符號(hào)所指內(nèi)容占據(jù)空間的大小(變量的大小,函數(shù)的大小) st_info; //它的高4位表示 Symbol Binding,低4位表示 Symbol Type st_other; st_shndx; //可重定向文件(.ko):對(duì)應(yīng)節(jié)區(qū)的在節(jié)區(qū)組中的下標(biāo),和st_value組合使用 -
重定位節(jié)(rela section)
為需要重新計(jì)算地址的地方提供定位信息
一般體現(xiàn)為引用外部函數(shù)時(shí),加載到內(nèi)存時(shí)需要重新定位外部函數(shù)的地址
.text 的重定位信息在 .rela_text, 以此類(lèi)推
每個(gè)entry的結(jié)構(gòu);
typedef struct { Elf64_Addr r_offset; /* 重定位文件 表示要重定位的地方,相對(duì)于對(duì)應(yīng)節(jié)區(qū)的起始地址的相對(duì)地址;可執(zhí)行文件 表示要重定位的地方的地址*/ Elf64_Xword r_info; /* 低32位表示重定向的類(lèi)型,高32位表示符號(hào)在符號(hào)表中的下標(biāo) */ Elf64_Sxword r_addend; } Elf64_Rela# 計(jì)算公式: # R_386_64(1) result = S + A + r_addend(64位才有); # R_386_PC64(2) result = S - P + A + r_addend(64位才有); # result: 重定向后填入P指向位置的值,即替換result的值 # P:要被重定位地方的地址偏移,即 r_offset + 相應(yīng)節(jié)區(qū)的起始地址 # A:要被重定位地方記錄的數(shù)值 # S:r_info找到的符號(hào)的地址,.o st_value + section_baseaddr, 可執(zhí)行文件 st_value root:~$ readelf -x 20 ./crc32c-intel.koHex dump of section '__jump_table':NOTE: This section has relocations against it, but these have NOT been applied to this dump.0x00000000 00000000 00000000 00000000 00000000 ................0x00000010 00000000 00000000 ........root:~$ readelf -x 21 ./crc32c-intel.koHex dump of section '.rela__jump_table':0x00000000 00000000 00000000 01000000 02000000 ................0x00000010 77030000 00000000 08000000 00000000 w...............0x00000020 01000000 02000000 7e030000 00000000 ........~.......0x00000030 10000000 00000000 01000000 d7000000 ................0x00000040 00000000 00000000 ........root:~$ readelf -r ./crc32c-intel.ko ... Relocation section '.rela__jump_table' at offset 0x2bd8 contains 3 entries:Offset Info Type Sym. Value Sym. Name + Addend 000000000000 000200000001 R_X86_64_64 0000000000000000 .text + 377 000000000008 000200000001 R_X86_64_64 0000000000000000 .text + 37e 000000000010 00d700000001 R_X86_64_64 0000000000000000 retp_enabled_key + 0 ...重定位的大致過(guò)程
section header table(Shdr)
ELF格式探析之三:sections - JollyWing - 博客園 (cnblogs.com)
.symtab(符號(hào)表,section的一種)
重定位信息
(37條消息) Linux系統(tǒng)–ELF文件之可重定位文件(Relocatable file)解析_Barry-CSDN博客
理解例子
查看elf文件信息
readelf 依賴(lài) binutils:http://ftp.gnu.org/gnu/binutils/
-
ELF header的信息:readelf -h
jingl@JingL$ readelf -h ./crc32c-intel.ko 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: REL (Relocatable file)Machine: Advanced Micro Devices X86-64Version: 0x1Entry point address: 0x0Start of program headers: 0 (bytes into file)Start of section headers: 19784 (bytes into file)Flags: 0x0Size of this header: 64 (bytes)Size of program headers: 0 (bytes)Number of program headers: 0Size of section headers: 64 (bytes)Number of section headers: 29Section header string table index: 28 -
program header信息: readelf -l
-
Section 信息:readelf -S
jingl@JingL$ readelf -S ./crc32c-intel.ko There are 29 section headers, starting at offset 0x4d48:Section Headers:[Nr] Name Type Address OffsetSize EntSize Flags Link Info Align[ 0] NULL 0000000000000000 000000000000000000000000 0000000000000000 0 0 0[ 1] .note.gnu.build-i NOTE 0000000000000000 000000400000000000000024 0000000000000000 A 0 0 4 ...[28] .shstrtab STRTAB 0000000000000000 00004c200000000000000121 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) -
查看某一段的數(shù)據(jù):readelf -x num
jingl@JingL$ readelf -x 8 ./crc32c-intel.koHex dump of section '.altinstr_replacement':0x00000000 0faee8ff e7 .....jingl@JingL$ readelf -x 11 ./crc32c-intel.koHex dump of section '.altinstructions':NOTE: This section has relocations against it, but these have NOT been applied to this dump.0x00000000 00000000 00000000 7d000200 00000000 ........}.......0x00000010 00000000 ed001105 ........jingl@JingL$ readelf -x 12 ./crc32c-intel.koHex dump of section '.rela.altinstructions':0x00000000 00000000 00000000 02000000 03000000 ................0x00000010 41000000 00000000 0c000000 00000000 A...............0x00000020 02000000 02000000 7e030000 00000000 ........~.......0x00000030 10000000 00000000 02000000 05000000 ................0x00000040 00000000 00000000 ........jingl@JingL$ readelf -x 20 ./crc32c-intel.koHex dump of section '__jump_table':NOTE: This section has relocations against it, but these have NOT been applied to this dump.0x00000000 00000000 00000000 00000000 00000000 ................0x00000010 00000000 00000000 ........jingl@JingL$ readelf -x 21 ./crc32c-intel.koHex dump of section '.rela__jump_table':0x00000000 00000000 00000000 01000000 02000000 ................0x00000010 77030000 00000000 08000000 00000000 w...............0x00000020 01000000 02000000 7e030000 00000000 ........~.......0x00000030 10000000 00000000 01000000 d7000000 ................0x00000040 00000000 00000000 ........ -
Symbol table 信息:readelf -s
jingl@JingL$ readelf -s./crc32c-intel.koSymbol table '.symtab' contains 222 entries:Num: Value Size Type Bind Vis Ndx Name0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND1: 0000000000000000 0 SECTION LOCAL DEFAULT 1 ...220: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND boot_cpu_data221: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __kernel_fpu_end -
重定位信息:readelf -r
root:~$ readelf -r ./crc32c-intel.ko ... Relocation section '.rela__jump_table' at offset 0x2bd8 contains 3 entries:Offset Info Type Sym. Value Sym. Name + Addend 000000000000 000200000001 R_X86_64_64 0000000000000000 .text + 377 000000000008 000200000001 R_X86_64_64 0000000000000000 .text + 37e 000000000010 00d700000001 R_X86_64_64 0000000000000000 retp_enabled_key + 0 ... -
反匯編 代碼段:objdum -d
-
刪除elf文件中的段:strip <option[s]> <in-file[s]>
-s --strip-allRemove all symbol and relocation information注: 刪除其他符號(hào)表段和調(diào)試信息段,但不刪除 .shstrtab 段-g -S -d --strip-debugRemove all debugging symbols & sections這幾個(gè)選項(xiàng)的功能是一樣,即移除上述5個(gè)".debug_"開(kāi)頭的調(diào)試信息段,仍會(huì)保留符號(hào)表--only-keep-debugStrip everything but the debug information注:段的總數(shù)量沒(méi)有減少,但文件大小減少了;對(duì)比了"readelf -S"輸出中的"offset"段,發(fā)現(xiàn)其中前面若干段的offset都沒(méi)有變化,即size為0了。-R --remove-section=<name>Also remove section <name> from the output移除指定段,比如 strip --remove-section=.symtab a.outstrip --remove-section=.strtab a.out
常用選項(xiàng)如下:驅(qū)動(dòng)文件(.ko)可能包含調(diào)試信息(.debug_info,依賴(lài)config中的CONFIG_DEBUG_INFO配置),可以使用strip --strip-debug ./xxx.ko去除;
使用strip, eu-strip, objcopy等剝離與導(dǎo)回符號(hào)表及調(diào)試信息
compile kernel with debug info
總結(jié)
以上是生活随笔為你收集整理的Linux elf文件分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux:守护进程详解及实现
- 下一篇: linux 其他常用命令