Linux elf文件分析
目錄
- 前言
- elf文件格式
- 1、大致結構
- 2、ELF header(Ehdr)
- 3、Program Header Table(Phdr)
- 4、section header table(Shdr)
- 查看elf文件信息
前言
elf文件是儲存linux下可重定位文件(.o,.ko),可執行文件,共享目標文件(.so)的一種文件。
elf文件格式
1、大致結構
2、ELF header(Ehdr)
-
ELF header的定義可以在 /usr/include/elf.h 中找到。Elf32_Ehdr是32位 ELF header的結構體。Elf64_Ehdr是64位ELF header的結構體,兩者主要區別在于某些成員的長度不一樣;
-
Ehdr 各個成員的說明
e_ident[**] //elf標識 e_type; //elf類型(重定位文件rel(.o,.ko),可執行文件,共享目標文件dyn(.so)) e_ machine; //目標文件體系類型,即運行架構,如x86、riscv、arm等 e_version; //目標文件版本 e_entry; //elf入口地址 e_ phoff; //程序頭部偏移 e_shoff; //節區頭部偏移 e_flags; //處理器的特定標志,32位和64位Intel架構都沒有定義標志,因此eflags的值是0 e_ehsize; //ELF格式頭部大小 e_phentsize; //程序頭部表項大小 e_phnum; //程序頭表項個數,即segment數(各個segment連續存放) e_shentsize; //節區頭部表項大小 e_shnum; //節區表項個數,即section數(各個section連續存放) e_shstrndx; //str節區(symbol的名字)在節區中位置(inedx)//可以使用命令 readelf 文件名,幫助理解ELF header(Ehdr)
ELF文件解析(二):ELF header詳解 - JollyWing - 博客園 (cnblogs.com)
3、Program Header Table(Phdr)
-
將多個section 再包一層,各個成員說明
p_type; //segment類型,segment就是一些段信息(.text,.rodata..),//一個segment包含多個section p_offset; //segment在文件中的偏移 p_vaddr; //segment虛地址 p_paddr; //物理地址 p_filesz; //文件中segment字節數 p_memsz; //內存中segment字節數 p_flags; p_align;
注意:一般只有可執行文件才有(有錯請指出)
4、section header table(Shdr)
-
section header結構體的定義可以在 /usr/include/elf.h
-
Shdr 各成員說明
sh_name; //一個索引值,在shstrtable(section header string table,包含section name的字符串表,也是一個section)中的索引 sh_type; //節區種類,如rel* sh_flags; //可寫,可分配,可執行等屬性 sh_addr; //如果section會出現在進程的內存映像中,給出了section第一字節的虛擬地址;Relocatable file 的虛存地址都為0。Executable file 和 Shared object file 才會為有需要的 Section 計算虛存地址 sh_offset; //給出節區第一個字節在elf文件中的偏移 sh_size; //節區大小 sh_link; //給出字節頭部表索引鏈接 sh_info; //給出節區附加信息 sh_addralign; //地址對齊約束 sh_entsize; //給出對于某些有固定項目的大小,如符號表,這個值給出了每個記錄大小。//一個可執行文件中包含多個section段(對應源文件中使用section定義的段,鏈接腳本會定義哪些段為代碼),一個section中有可能有多個函數(多段代碼使用一個section定義) //可以使用命令 objdump -s -d 文件名,查看文件的的section信息,幫助理解 -
.symtab(符號表,section的一種),符號表中每個entry 的結構如下:
st_name; //一個索引值,在shstrtable(section header string table,包含section name的字符串表,也是一個section)中的索引 st_value; //可重定向文件(.ko):相對于節起始地址的偏移。//可執行文件(vmlinux):絕對地址。 st_size; //符號所指內容占據空間的大小(變量的大小,函數的大小) st_info; //它的高4位表示 Symbol Binding,低4位表示 Symbol Type st_other; st_shndx; //可重定向文件(.ko):對應節區的在節區組中的下標,和st_value組合使用 -
重定位節(rela section)
為需要重新計算地址的地方提供定位信息
一般體現為引用外部函數時,加載到內存時需要重新定位外部函數的地址
.text 的重定位信息在 .rela_text, 以此類推
每個entry的結構;
typedef struct { Elf64_Addr r_offset; /* 重定位文件 表示要重定位的地方,相對于對應節區的起始地址的相對地址;可執行文件 表示要重定位的地方的地址*/ Elf64_Xword r_info; /* 低32位表示重定向的類型,高32位表示符號在符號表中的下標 */ Elf64_Sxword r_addend; } Elf64_Rela# 計算公式: # 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 + 相應節區的起始地址 # A:要被重定位地方記錄的數值 # S:r_info找到的符號的地址,.o st_value + section_baseaddr, 可執行文件 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 ...重定位的大致過程
section header table(Shdr)
ELF格式探析之三:sections - JollyWing - 博客園 (cnblogs.com)
.symtab(符號表,section的一種)
重定位信息
(37條消息) Linux系統–ELF文件之可重定位文件(Relocatable file)解析_Barry-CSDN博客
理解例子
查看elf文件信息
readelf 依賴 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) -
查看某一段的數據: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注: 刪除其他符號表段和調試信息段,但不刪除 .shstrtab 段-g -S -d --strip-debugRemove all debugging symbols & sections這幾個選項的功能是一樣,即移除上述5個".debug_"開頭的調試信息段,仍會保留符號表--only-keep-debugStrip everything but the debug information注:段的總數量沒有減少,但文件大小減少了;對比了"readelf -S"輸出中的"offset"段,發現其中前面若干段的offset都沒有變化,即size為0了。-R --remove-section=<name>Also remove section <name> from the output移除指定段,比如 strip --remove-section=.symtab a.outstrip --remove-section=.strtab a.out
常用選項如下:驅動文件(.ko)可能包含調試信息(.debug_info,依賴config中的CONFIG_DEBUG_INFO配置),可以使用strip --strip-debug ./xxx.ko去除;
使用strip, eu-strip, objcopy等剝離與導回符號表及調試信息
compile kernel with debug info
總結
以上是生活随笔為你收集整理的Linux elf文件分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux:守护进程详解及实现
- 下一篇: TCP的定时器系列 — 保活定时器(有图