ELF 文件格式介绍

来源:互联网 发布:wine for ubuntu下载 编辑:程序博客网 时间:2024/06/18 15:03

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

1、文件结构视图



2、elf重定义的数据类型

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

7  /* 32-bit ELF base types. */8  typedef __u32Elf32_Addr;9  typedef __u16Elf32_Half;10  typedef __u32Elf32_Off;11  typedef __s32Elf32_Sword;12  typedef __u32Elf32_Word;13  14  /* 64-bit ELF base types. */15  typedef __u64Elf64_Addr;16  typedef __u16Elf64_Half;17  typedef __s16Elf64_SHalf;18  typedef __u64Elf64_Off;19  typedef __s32Elf64_Sword;20  typedef __u32Elf64_Word;21  typedef __u64Elf64_Xword;22  typedef __s64Elf64_Sxword;
知道了重定义的数据类型,我们才知道对应的结构体占用的字节数,方便读取和解析文件

3、elf文件的文件头

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

201  #define EI_NIDENT16202  203  typedef struct elf32_hdr{204    unsigned chare_ident[EI_NIDENT];205    Elf32_Halfe_type;206    Elf32_Halfe_machine;207    Elf32_Worde_version;208    Elf32_Addre_entry;  /* Entry point */209    Elf32_Offe_phoff;210    Elf32_Offe_shoff;211    Elf32_Worde_flags;212    Elf32_Halfe_ehsize;213    Elf32_Halfe_phentsize;214    Elf32_Halfe_phnum;215    Elf32_Halfe_shentsize;216    Elf32_Halfe_shnum;217    Elf32_Halfe_shstrndx;218  } Elf32_Ehdr;219  220  typedef struct elf64_hdr {221    unsigned chare_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   065  #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 0xff0070  #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_Wordp_type;245    Elf32_Offp_offset;246    Elf32_Addrp_vaddr;247    Elf32_Addrp_paddr;248    Elf32_Wordp_filesz;249    Elf32_Wordp_memsz;250    Elf32_Wordp_flags;251    Elf32_Wordp_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  0x7000000036  #define PT_HIPROC  0x7fffffff37  #define PT_GNU_EH_FRAME0x6474e55038  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_Wordsh_name;304    Elf32_Wordsh_type;305    Elf32_Wordsh_flags;306    Elf32_Addrsh_addr;307    Elf32_Offsh_offset;308    Elf32_Wordsh_size;309    Elf32_Wordsh_link;310    Elf32_Wordsh_info;311    Elf32_Wordsh_addralign;312    Elf32_Wordsh_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;i<num;i++){    segmentType=fReader.readInt();    if(segmentType==PT_INTERP){    segmentFlags=fReader.readInt();    segmentOffset=fReader.readLong();    System.out.print("["+i+"]\t"+        segmentType+"\t"+        segmentFlags+"\t"+        segmentOffset+"\t");    System.out.print(""+                    fReader.readLong()+"\t"+        fReader.readLong()+"\t");    segmentSize=fReader.readLong();    System.out.println(""+    segmentSize+"\t"+        fReader.readLong()+"\t"+                    fReader.readLong());    }else{    System.out.println("["+i+"]\t"+    segmentType+"\t"+                fReader.readInt()+"\t"+    fReader.readLong()+"\t"+                fReader.readLong()+"\t"+    fReader.readLong()+"\t"+                fReader.readLong()+"\t"+    fReader.readLong()+"\t"+                fReader.readLong());    }    }    if(segmentSize>0){  //PT_INTERPSystem.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<num;i++){    System.out.println("["+i+"]\t"+                fReader.readInt()+"\t"+                fReader.readInt()+"\t"+    fReader.readLong()+"\t"+                fReader.readLong()+"\t"+    fReader.readLong()+"\t"+                fReader.readLong()+"\t"+                fReader.readInt()+"\t"+                fReader.readInt()+"\t"+    fReader.readLong()+"\t"+                fReader.readLong());    }    }        }        private void readELFShStr(FileInputReader fReader,long offset,int size,int index){    System.out.println();    System.out.println("-------------- section string table --------------");    long shStrOffset=offset+ size* index;      if(fReader.markAndReset(shStrOffset)){            fReader.readInt();            fReader.readInt();fReader.readLong();            fReader.readLong();long strOffset=fReader.readLong();            int strSize=(int)fReader.readLong();            if(fReader.markAndReset(strOffset)){            byte[] strBytes=fReader.readBytes(strSize);            String str=new String(strBytes);            String[] ss=str.split("\0");            System.out.println("index\t value");            for(int i=0;i<ss.length;i++){            System.out.println("["+i+"]\t"+ss[i]);            }            }    }        }private void printfBytes(String tag,byte[] bs){System.out.print(tag+":\t");for(byte b:bs){System.out.print(" "+b);}System.out.println();}private void printfShort(String tag,short s){System.out.println(tag+":\t"+s);}private void printfInt(String tag,int i){System.out.println(tag+":\t"+i);}private void printfLong(String tag,long l){System.out.println(tag+":\t"+l);}class FileInputReader{private FileInputStream mFin;private File mFile;FileInputReader(File file){this.mFile=file;try {this.mFin=new FileInputStream(mFile);} catch (FileNotFoundException e) {e.printStackTrace();}}boolean markAndReset(long pos){try {close();mFin=new FileInputStream(mFile);mFin.skip(pos);return true;} catch (Exception e) {e.printStackTrace();}return false;}int readByte(){try {return mFin.read();} catch (Exception e) {e.printStackTrace();}return ERROR;}short readShort(){try {int byte0=mFin.read();int byte1=mFin.read();return (short)((byte1<<8)|byte0);} catch (Exception e) {e.printStackTrace();}return ERROR;}int readInt(){try {int byte0=mFin.read();int byte1=mFin.read();int byte2=mFin.read();int byte3=mFin.read();return ((byte3<<24)|(byte2<<16)|(byte1<<8)|byte0);} catch (Exception e) {e.printStackTrace();}return ERROR;}long readLong(){try {int byte0=mFin.read();int byte1=mFin.read();int byte2=mFin.read();int byte3=mFin.read();int byte4=mFin.read();  //no need ??int byte5=mFin.read();  //no need ??int byte6=mFin.read();  //no need ??int byte7=mFin.read();  //no need ??return ((byte3<<24)|(byte2<<16)|(byte1<<8)|byte0);} catch (Exception e) {e.printStackTrace();}return ERROR;}byte[] readBytes(int size){try {byte[] bytes=new byte[size];mFin.read(bytes);return bytes;} catch (Exception e) {e.printStackTrace();}return new byte[0];}void close(){try {if(mFin!=null) mFin.close();} catch (IOException e) {e.printStackTrace();}}}}

运行结果

-------------- elf header --------------e_ident: 127 69 76 70 2 1 1 0 0 0 0 0 0 0 0 0e_type:3e_machine:183e_version:1e_entry:9924e_phoff;:64e_shoff:33240e_flags:0e_ehsize:64e_phentsize:56e_phnum:9e_shentsize:64e_shnum:29e_shstrndx:28-------------- program header --------------indexp_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align[0]646464645045048[1]3456856856821211[2]1500028932289324096[3]16306083470434704218422724096[4]263132835424354246246248[5]4459259259256564[6]1685382480428864288642886468684[7]16853824816000000[8]16853824826306083470434704216021608-------------- interp segment --------------interp is:/system/bin/linker64-------------- section header --------------indexsh_name sh_type sh_flags sh_add sh_offset sh_size sh_link sh_info sh_addralign sh_entsize[0]0000000000[1]1112568568210010[2]1972592592240040[3]3972616616320040[4]58112648648242451824[5]66323072307221710010[6]741879048182252485248644080[7]8418790481912531253122024022[8]971879048190255165516805240[9]112425600560076840824[10]122466636863682064411824[11]1271684328432140800816[12]1321698409840125640040[13]13812224042240461070040[14]1461228512285123520080[15]156122886428864680040[16]1701633470430608160080[17]1851433472030624160080[18]1971533473630640160080[19]2091334752306566720080[20]22263354243132862450816[21]2311336048319521040080[22]2361336152320567120080[23]245133686432768240080[24]251833688832792880080[25]256148032792990011[26]26570032892280040[27]28810032920120010[28]1300329323030010-------------- 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






原创粉丝点击