ELF 文件格式介绍

ELF文件是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件。由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。

1、文件结构视图

ELF 文件格式介绍_第1张图片


2、elf重定义的数据类型

在linux-4.10/include/uapi/linux/elf.h

7  /* 32-bit ELF base types. */
8  typedef __u32	Elf32_Addr;
9  typedef __u16	Elf32_Half;
10  typedef __u32	Elf32_Off;
11  typedef __s32	Elf32_Sword;
12  typedef __u32	Elf32_Word;
13  
14  /* 64-bit ELF base types. */
15  typedef __u64	Elf64_Addr;
16  typedef __u16	Elf64_Half;
17  typedef __s16	Elf64_SHalf;
18  typedef __u64	Elf64_Off;
19  typedef __s32	Elf64_Sword;
20  typedef __u32	Elf64_Word;
21  typedef __u64	Elf64_Xword;
22  typedef __s64	Elf64_Sxword;
知道了重定义的数据类型,我们才知道对应的结构体占用的字节数,方便读取和解析文件

3、elf文件的文件头

该结构体定义在   linux-4.10/include/uapi/linux/elf.h

201  #define EI_NIDENT	16
202  
203  typedef struct elf32_hdr{
204    unsigned char	e_ident[EI_NIDENT];
205    Elf32_Half	e_type;
206    Elf32_Half	e_machine;
207    Elf32_Word	e_version;
208    Elf32_Addr	e_entry;  /* Entry point */
209    Elf32_Off	e_phoff;
210    Elf32_Off	e_shoff;
211    Elf32_Word	e_flags;
212    Elf32_Half	e_ehsize;
213    Elf32_Half	e_phentsize;
214    Elf32_Half	e_phnum;
215    Elf32_Half	e_shentsize;
216    Elf32_Half	e_shnum;
217    Elf32_Half	e_shstrndx;
218  } Elf32_Ehdr;
219  
220  typedef struct elf64_hdr {
221    unsigned char	e_ident[EI_NIDENT];	/* ELF "magic number" */
222    Elf64_Half e_type;
223    Elf64_Half e_machine;
224    Elf64_Word e_version;
225    Elf64_Addr e_entry;		/* Entry point virtual address */
226    Elf64_Off e_phoff;		/* Program header table file offset */
227    Elf64_Off e_shoff;		/* Section header table file offset */
228    Elf64_Word e_flags;
229    Elf64_Half e_ehsize;
230    Elf64_Half e_phentsize;
231    Elf64_Half e_phnum;
232    Elf64_Half e_shentsize;
233    Elf64_Half e_shnum;
234    Elf64_Half e_shstrndx;
235  } Elf64_Ehdr;

Elf32_Ehdr和Elf64_Ehdr 结构体的成员是相同的,只是类型可能不同而已。

1)e_ident[EI_NIDENT] 长度为16 char数组,可以理解为文件的标识

2)e_type 该elf文件的类型

/* These constants define the different elf file types */
64  #define ET_NONE   0
65  #define ET_REL    1  //可重定位文件,一般是编译后的.o文件
66  #define ET_EXEC   2  //
67  #define ET_DYN    3  //
68  #define ET_CORE   4  //coredump文件
69  #define ET_LOPROC 0xff00
70  #define ET_HIPROC 0xffff

3)e_machine 运行时所需的cpu体系结构

4)e_version 文件的版本

5)e_entry; 可执行程序的入口地址

6)e_phoff 程序头表(programheader table)相对于文件开始位置的偏移量

7)e_shoff 节头表(sectionheader table)相对于文件开始位置的偏移量

8)e_flags相关文件的特定处理器标志

9)e_ehsize elf header的大小

10)e_phentsize  程序头表(program headertable)中每一项的大小

11)e_phnum  程序头表的数目,也就是有多少项

12)e_shentsize节头表(sectionheader table)中每一项的大小

13)e_shnum  节头表的数目,也就是有多少项

14)e_shstrndx   节名字字符表在节头表(sectionheader table)中的索引,也就是在那一项


4、elf文件中的程序头表

该结构体定义在   linux-4.10/include/uapi/linux/elf.h

typedef struct elf32_phdr{
244    Elf32_Word	p_type;
245    Elf32_Off	p_offset;
246    Elf32_Addr	p_vaddr;
247    Elf32_Addr	p_paddr;
248    Elf32_Word	p_filesz;
249    Elf32_Word	p_memsz;
250    Elf32_Word	p_flags;
251    Elf32_Word	p_align;
252  } Elf32_Phdr;
253  
254  typedef struct elf64_phdr {
255    Elf64_Word p_type;
256    Elf64_Word p_flags;
257    Elf64_Off p_offset;		/* Segment file offset */
258    Elf64_Addr p_vaddr;		/* Segment virtual address */
259    Elf64_Addr p_paddr;		/* Segment physical address */
260    Elf64_Xword p_filesz;		/* Segment size in file */
261    Elf64_Xword p_memsz;		/* Segment size in memory */
262    Elf64_Xword p_align;		/* Segment alignment, file & memory */
263  } Elf64_Phdr;

1)p_type描述的段的类型

25  #define PT_NULL    0  //未使用
26  #define PT_LOAD    1  //可加载段
27  #define PT_DYNAMIC 2  //给出动态链接的信息
28  #define PT_INTERP  3   //解释器段
29  #define PT_NOTE    4  //附加信息的位置和大小
30  #define PT_SHLIB   5   //保留
31  #define PT_PHDR    6  //程序头表自身位置和大小
32  #define PT_TLS     7               /* Thread local storage segment */
33  #define PT_LOOS    0x60000000      /* OS-specific */
34  #define PT_HIOS    0x6fffffff      /* OS-specific */
35  #define PT_LOPROC  0x70000000
36  #define PT_HIPROC  0x7fffffff
37  #define PT_GNU_EH_FRAME		0x6474e550
38  
39  #define PT_GNU_STACK	(PT_LOOS + 0x474e551)

2)p_flags 此成员给出与段相关的标志

3)p_offset 此成员给出从文件头到该段第一个字节的偏移

4)p_vaddr 此成员给出段的第一个字节将被放到内存中的虚拟地址

5)p_paddr此成员仅用于与物理地址相关的系统中

6)p_filesz 此成员给出段在文件映像中所占的字节数

7)p_memsz 此成员给出段在内存映像中占用的字节数

8)p_align给出段在文件中和内存中如何对齐,数值 0 和 1 表示不需要对齐

程序表头中的每一项,就是上面文件结构视图中的一个segment,一个segment 可能包含多个section。


5、elf文件中的节头表

elf文件中的程序表头

typedef struct elf32_shdr {
303    Elf32_Word	sh_name;
304    Elf32_Word	sh_type;
305    Elf32_Word	sh_flags;
306    Elf32_Addr	sh_addr;
307    Elf32_Off	sh_offset;
308    Elf32_Word	sh_size;
309    Elf32_Word	sh_link;
310    Elf32_Word	sh_info;
311    Elf32_Word	sh_addralign;
312    Elf32_Word	sh_entsize;
313  } Elf32_Shdr;
314  
315  typedef struct elf64_shdr {
316    Elf64_Word sh_name;		/* Section name, index in string tbl */
317    Elf64_Word sh_type;		/* Type of section */
318    Elf64_Xword sh_flags;		/* Miscellaneous section attributes */
319    Elf64_Addr sh_addr;		/* Section virtual addr at execution */
320    Elf64_Off sh_offset;		/* Section file offset */
321    Elf64_Xword sh_size;		/* Size of section in bytes */
322    Elf64_Word sh_link;		/* Index of another section */
323    Elf64_Word sh_info;		/* Additional section information */
324    Elf64_Xword sh_addralign;	/* Section alignment */
325    Elf64_Xword sh_entsize;	/* Entry size if section holds table */
326  } Elf64_Shdr;

1)sh_name 节的名称,在节区头部字符串中的索引

2)sh_type 节区内容的分类

3)sh_flags节的属性

4)sh_addr如果此节的内容将出现在进程空间里,这个字段给出了该节在内存中起始地址。

5)sh_offset如果此节在文件中占用一定的字节,这个字段给出了该节在整个文件中的起始偏移量。

6)sh_size如果此节在文件中占用一定的字节,这个字段给出了该节在文件中的字节大小

7)sh_link如果另一个节与这个节相关联,这个字段给出了相关的节在节头中的索引

8)sh_info 附加信息

9)sh_addralign地址对齐。

10)sh_entsize  代表字节大小的数,对某些节才有意义


6、elf 文件解析程序及运行结果

package hxiong;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ELFReader {

	public static final String ELF_FILE_PATH="E:\\private\\AOSP\\ndk\\tool\\readelf\\logcat";
	
	public static final String ELF_=""; 
	public static final String ELF_IDENT="e_ident"; 
	public static final String ELF_TYPE="e_type"; 
	public static final String ELF_MACHINE="e_machine"; 
	public static final String ELF_VERSION="e_version"; 
	public static final String ELF_ENTRY="e_entry"; 
	public static final String ELF_PHOFF="e_phoff;"; 
	public static final String ELF_SHOFF="e_shoff"; 
	public static final String ELF_FLAGS="e_flags"; 
	public static final String ELF_EHSIZE="e_ehsize"; 
	public static final String ELF_PHENTSIZE="e_phentsize"; 
	public static final String ELF_PHNUM="e_phnum"; 
	public static final String ELF_SHENTSIZE="e_shentsize"; 
	public static final String ELF_SHNUM="e_shnum"; 
	public static final String ELF_SHSTRNDX="e_shstrndx"; 
	
	//
	public static final int ELF_32=1;
	public static final int ELF_64=2;
	
	public static final int ERROR=-1;
	
	 /* These constants are for the segment types stored in the image headers */

	public static final int PT_LOAD    = 1;
	public static final int PT_DYNAMIC = 2;
	public static final int PT_INTERP  = 3;

	
	public static void main(String[] args) {
		
		ELFReader elfReader=new ELFReader();
		elfReader.readELF(ELF_FILE_PATH);
	}
	
	public void readELF(String elfPath){
		File file=new File(elfPath);
		if(file.exists()&&file.isFile()){
			readELF(file);
		}else{
			System.out.println("error:"+elfPath+"is not exit or not a file.");
		}	
	}
	
	private void readELF(File elfFile){
		if(elfFile==null){
			System.out.println("error:elfFile is null.");
		}else{
			FileInputReader fReader=new FileInputReader(elfFile);
			readELF(fReader);
			fReader.close();
		}
	}
	
	
	
	private void readELF(FileInputReader fReader){
		byte[] ident=fReader.readBytes(16);
		System.out.println("-------------- elf header --------------");
		printfBytes(ELF_IDENT,ident);
		if(ident[4]==ELF_32){
			readELF32(fReader);
		}else if(ident[4]==ELF_64){
			readELF64(fReader);
		}else{
			System.out.println("error:unknown type.");
		}	
	}
	//elf32文件的解析就不写出来了,参照elf64的解析过程即可
	private void readELF32(FileInputReader fReader){
		
	}
	
    private void readELF64(FileInputReader fReader){
    	 printfShort(ELF_TYPE,fReader.readShort());
    	 printfShort(ELF_MACHINE,fReader.readShort());	
    	 printfInt(ELF_VERSION,fReader.readInt());
    	 long elfEntry=fReader.readLong();
    	 long elfPhOff=fReader.readLong();
    	 long elfShOff=fReader.readLong();
    	 printfLong(ELF_ENTRY,elfEntry);
    	 printfLong(ELF_PHOFF,elfPhOff);
    	 printfLong(ELF_SHOFF,elfShOff);
    	 printfInt(ELF_FLAGS,fReader.readInt());
    	 printfShort(ELF_EHSIZE,fReader.readShort());
    	 short elfPhSize=fReader.readShort();
    	 short elfPhNum=fReader.readShort();
    	 short elfShSize=fReader.readShort();
    	 short elfShNum=fReader.readShort();
    	 short elfShStrIndx=fReader.readShort();
    	 printfShort(ELF_PHENTSIZE,elfPhSize);
    	 printfShort(ELF_PHNUM,elfPhNum);
    	 printfShort(ELF_SHENTSIZE,elfShSize);
    	 printfShort(ELF_SHNUM,elfShNum);
    	 printfShort(ELF_SHSTRNDX,elfShStrIndx);
    	 
    	 if(elfPhNum>0){
    		 readELFProgramHeader(fReader,elfPhOff,(int)elfPhSize,(int)elfPhNum); 
    	 }
    	 
    	 if(elfShNum>0){
    		 readELFSectionHeader(fReader,elfShOff,(int)elfShSize,(int)elfShNum);
    	 }
    	 
    	 if(elfShStrIndx>0){
    		 readELFShStr(fReader,elfShOff,(int)elfShSize,(int)elfShStrIndx);
    	 }
	}
    
    private void readELFProgramHeader(FileInputReader fReader,long offset,int size,int num){
    	System.out.println();
    	System.out.println("-------------- program header --------------");
    	int segmentType=0;
    	int segmentFlags=0;
    	long segmentOffset=0;
    	long segmentSize=0;
    	if(fReader.markAndReset(offset)){
    		System.out.println("index\tp_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align");
    		for(int i=0;i0){  //PT_INTERP
				System.out.println();
		    	System.out.println("-------------- interp segment --------------");
		    	if(fReader.markAndReset(segmentOffset)){
		    		byte[] segmentContent=fReader.readBytes((int)segmentSize);
		    		System.out.println("interp is:"+new String(segmentContent));
		    	}
			}
    	}
    }
    
    private void readELFSectionHeader(FileInputReader fReader,long offset,int size,int num){
    	System.out.println();
    	System.out.println("-------------- section header --------------");
    	if(fReader.markAndReset(offset)){
    		System.out.println("index\tsh_name sh_type sh_flags sh_add sh_offset sh_size sh_link sh_info sh_addralign sh_entsize");
    		for(int i=0;i

运行结果

-------------- elf header --------------
e_ident:	 127 69 76 70 2 1 1 0 0 0 0 0 0 0 0 0
e_type:	3
e_machine:	183
e_version:	1
e_entry:	9924
e_phoff;:	64
e_shoff:	33240
e_flags:	0
e_ehsize:	64
e_phentsize:	56
e_phnum:	9
e_shentsize:	64
e_shnum:	29
e_shstrndx:	28

-------------- program header --------------
index	p_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align
[0]	6	4	64	64	64	504	504	8
[1]	3	4	568	568	568	21	21	1
[2]	1	5	0	0	0	28932	28932	4096
[3]	1	6	30608	34704	34704	2184	2272	4096
[4]	2	6	31328	35424	35424	624	624	8
[5]	4	4	592	592	592	56	56	4
[6]	1685382480	4	28864	28864	28864	68	68	4
[7]	1685382481	6	0	0	0	0	0	0
[8]	1685382482	6	30608	34704	34704	2160	2160	8

-------------- interp segment --------------
interp is:/system/bin/linker64

-------------- section header --------------
index	sh_name sh_type sh_flags sh_add sh_offset sh_size sh_link sh_info sh_addralign sh_entsize
[0]	0	0	0	0	0	0	0	0	0	0
[1]	11	1	2	568	568	21	0	0	1	0
[2]	19	7	2	592	592	24	0	0	4	0
[3]	39	7	2	616	616	32	0	0	4	0
[4]	58	11	2	648	648	2424	5	1	8	24
[5]	66	3	2	3072	3072	2171	0	0	1	0
[6]	74	1879048182	2	5248	5248	64	4	0	8	0
[7]	84	1879048191	2	5312	5312	202	4	0	2	2
[8]	97	1879048190	2	5516	5516	80	5	2	4	0
[9]	112	4	2	5600	5600	768	4	0	8	24
[10]	122	4	66	6368	6368	2064	4	11	8	24
[11]	127	1	6	8432	8432	1408	0	0	8	16
[12]	132	1	6	9840	9840	12564	0	0	4	0
[13]	138	1	2	22404	22404	6107	0	0	4	0
[14]	146	1	2	28512	28512	352	0	0	8	0
[15]	156	1	2	28864	28864	68	0	0	4	0
[16]	170	16	3	34704	30608	16	0	0	8	0
[17]	185	14	3	34720	30624	16	0	0	8	0
[18]	197	15	3	34736	30640	16	0	0	8	0
[19]	209	1	3	34752	30656	672	0	0	8	0
[20]	222	6	3	35424	31328	624	5	0	8	16
[21]	231	1	3	36048	31952	104	0	0	8	0
[22]	236	1	3	36152	32056	712	0	0	8	0
[23]	245	1	3	36864	32768	24	0	0	8	0
[24]	251	8	3	36888	32792	88	0	0	8	0
[25]	256	1	48	0	32792	99	0	0	1	1
[26]	265	7	0	0	32892	28	0	0	4	0
[27]	288	1	0	0	32920	12	0	0	1	0
[28]	1	3	0	0	32932	303	0	0	1	0

-------------- section string table --------------
index	 value
[0]	
[1]	.shstrtab
[2]	.interp
[3]	.note.android.ident
[4]	.note.gnu.build-id
[5]	.dynsym
[6]	.dynstr
[7]	.gnu.hash
[8]	.gnu.version
[9]	.gnu.version_r
[10]	.rela.dyn
[11]	.rela.plt
[12]	.text
[13]	.rodata
[14]	.eh_frame
[15]	.eh_frame_hdr
[16]	.preinit_array
[17]	.init_array
[18]	.fini_array
[19]	.data.rel.ro
[20]	.dynamic
[21]	.got
[22]	.got.plt
[23]	.data
[24]	.bss
[25]	.comment
[26]	.note.gnu.gold-version
[27]	.gnu_debuglink






你可能感兴趣的:(elf,elf,elf文件格式)