ELF文件格式

在介绍ELF格式之前,先简单说明一下可执行文件的生成流程:1)编写C源文件,或汇编源文件;2)准备共享库格式的目标文件(shared object file),如数学库、标准库;2)用编译器(compiler)将C编译成可重定位格式的目标文件(relocatable object file),用汇编器(assembler)将汇编源文件编译成可重定位格式的目标文件;3)用连接器(linker)将第二步的共享个库文件和第三步生成的目标文件链接生成可执行文件(executable file)。

(也就是说,内存中程序存在的状态就是ELF格式,当自己编写某个程序,定义指针*p,则p+4的地址为p的地址加4,其实已经在编译时确定了p+4的大小,所以打印出来的地址是+4的,不出错,我yazhouren09的理解)

ELF(excutable and linking format)是一种可执行可链接格式的二进制文件,它可以用来表示relocatable file、executable file或者shared object file,这三者都是目标文件(object file)。所谓“可执行”指可以被调入内存供CPU直接运行;“可链接”指多个ELF格式的目标文件可以被链接在一起形成一个可执行文件。下图左边是可链接格式的ELF文件格式,右边是可执行格式的ELF文件格式。

无论是linking view还是execution view的ELF文件,他们都包含一个ELF Header,它包含文件的基本信息。ELF自定义了一些类型,并强制规定了他们所占的字节个数,以实现跨平台,如Elf32_Half占2字节、Elf32_Word占4字节、Elf32_Off占4字节等。


 1 typedef struct
 2 {
 3 unsigned char     e_ident[EI_NIDENT];     /* Magic number and other info */
 4 Elf32_Half        e_type;                  /*目标文件类型 */
 5 Elf32_Half        e_machine;               /*Architecture */
 6 Elf32_Word       e_version;               /* Object file version */
 7 Elf32_Addr       e_entry;                  /*入口地址 */
 8 Elf32_Off        e_phoff;                  /* Program header table文件偏移 */
 9 Elf32_Off        e_shoff;                  /* Section header table 文件偏移 */
10 Elf32_Word      e_flags;                  /* Processor-specific flags */
11 Elf32_Half       e_ehsize;                 /* ELF header 大小 */
12 Elf32_Half       e_phentsize;              /*每个Program header大小 */
13 Elf32_Half       e_phnum;                /*一共多少个Program header */
14 Elf32_Half       e_shentsize;             /* 每个Section header大小 */
15 Elf32_Half       e_shnum;               /*一共多少个 Section header */
16 Elf32_Half     e_shstrndx;     /*Section的字符表在section header table的索引值 */
17 } Elf32_Ehdr;
18
复制代码
e_ident[EI_NIDENT]是一个有16个字节的数组,e_ident[0]=0x7f,e_ident[1]=”E”,e_ident[2]=”L”, e_ident[3]=”F”, e_ident[4]指示ELFCLASS(0:ELFCLASSNONE;1:ELFCLASS32;2:ELFCLASS64),e_ident[5]指示程序中的数据格式(0:无效;1:小端;2:大端),e_ident[6]指示版本固定为0x1,e_ident[7]到e_ident[14]固定为0,e_ident[15]固定为16用于指示e_ident[]数组有16个元素。e_type指示该ELF文件的类型,占2字节,可以为ET_NONE(0, No file type)/ ET_REL(1, Relocatable file)/ ET_EXEC(2, Executable file)/ ET_DYN(3, Shared object file)/ ET_CORE(4, Core file)/ ET_LOPROC(0xff00, Processor-specific)/ ET_HIPROC(0xffff, Processor-specific),常见的是ET_EXEC、ET_DYN、ET_REL。e_machine定义CPU的指令集架构,ELF标准中定义的有EM_NONE(0)/ EM_M32(1)/ EM_SPARC(2)/ EM_386(3)/ EM_68K(4)/ EM_88K(5)/ EM_860(6)/EM_MIPS(7),其它的值保留,有用户使用,比如EM_OR32=0x8472。e_version定义该ELF文件的版本号。e_entry定义程序的启动地址,也即CPU启动后读取的第一条指令所在的地址。e_phoff定义代表Program header table的数据结构在文件中的以字节为单位的偏移量,为0表示没有Program header table。e_shoff定义代表Section header table数据结构在文件中的以字节为单位的偏移量,为0表示没有Section header table。e_flags定义了和CPU相关的一些参数,不同的CPU对e_flags的定义是不一样的。e_ehsize定义ELF header这个数据结构的以字节为单位的实际大小,之所以出现这个参数,是因为各个平台上ELF自定义类型所表示的字节数不同。一个Program header table包含多个entry即多个Program header,每个entry的占用的文件字节数相同,e_phentsize定义了每个entry的大小,e_phnum定义当前Program header table中entry的个数。一个Section header table包含多个entry即多个Section header,每个entry的占用的文件字节数相同,e_shentsize定义了每个entry的大小,e_shnum定义当前Section header table中entry的个数。在Section header table中有一个特殊的entry,它定义了Section header table中各个entry的名字,e_shstrndx用于指示这个特殊的entry在Section header table中的索引,即它在第几个entry,这个特殊的entry称为section name string table。
Code
复制代码

前面已经提到,Section header table有多个entry,其实每个entry都是一个Elf32_Shdr类型数据结构,用这个数据结构可以找到每个Section在文件中的位置,e_shentsize=sizeof(Elf32_Shdr),e_shnum=numof(Elf32_Shdr)。sh_name是一个字符串数组的索引,它指示当前Section header所描述的这个Section的名字在Section name string table中的位置。sh_type指示当前Section header的类型,SHT_NULL(0,该Section header所指示的section无效,不占用文件空间)/ SHT_PROGBITS(1,该Section header所指示的section包含程序指令)/ SHT_SYMTAB(2,该Section header所指示的section包含重定位符号表)/ SHT_STRTAB(3,该Section header所指示的section包含字符表)/ SHT_RELA(4,重定位相关,用于链接过程)/ SHT_HASH(5,重定位相关,用于链接过程)/ SHT_DYNAMIC(6,用于链接过程)/ SHT_NOTE(7,信息说明)/ SHT_NOBITS(8,,该Section header所指示的section不占用文件字节,除此之外和SHT_PROGBITS含义相同) /SHT_REL(9,重定位相关)/ SHT_SHLIB(10,保留类型)/ SHT_DYNSYM(11,重定位相关)/ SHT_LOPROC(0x70000000)- SHT_HIPROC(0x7fffffff)(这一范围的类型值跟CPU相关)/ SHT_LOUSER(0x80000000)- SHT_HIUSER(0xffffffff)(这一范围的类型值保留给应用程序)。sh_flags指示当前Section header所对应的section的属性,WRITE(0x1,当前Section header所对应的section包含可写的数据)/ALLOC(0x2,当前Section header所对应的section在程序执行时占用实际的存储空间)/EXECINSTR(0x4,当前Section header所对应的section包含可执行的指令)/MASKPROC(0xf0000000,保留)。sh_addr指示当前Section header所对应的section在内存中起始地址。sh_offset指示当前Section header所对应的section在文件中以字节为单位的偏移量。sh_size指示当前Section header所对应的section在文件中占用的字节数。sh_link和sh_info供链接器使用。sh_addralign指示对sh_addr的对其要求。有一些特殊的section,它内部仍然包含多个entry,每个entry大小相同,如symbol table,sh_entsize用于指示这个特殊的section中每个entry的大小。

Code
复制代码

上表列出了一些常见的section。.bss中,包含未初始化的全局数据变量,这些变量不占用ELF文件的空间(SHT_NOBITS),但占用实际内存空间(SHF_ALLOC),在程序运行启动时由OS负责初始化为0。.comment包含版本控制信息。.data和.data1包含已经初始化的全局数据变量,这些变量占用ELF文件空间,也占用实际内存空间。.fini包含主函数退出时执行的指令。.init包含主函数执行前所执行的指令。.rodata和.rodata1包含只读数据。.shstrtab包含section header string table。.text包含程序指令。

typedef struct
{
Elf32_Word     p_type;      /* Segment type */
Elf32_Off       p_offset;      /* Segment offset in file */
Elf32_Addr    p_vaddr;      /* Segment virtual address in memory*/
Elf32_Addr     p_paddr;      /* Segment physical address */
Elf32_Word     p_filesz;      /* Segment size in file */
Elf32_Word     p_memsz;     /* Segment size in memory */
Elf32_Word     p_flags;       /* Segment flags */
Elf32_Word     p_align;      /* Segment alignment */
} Elf32_Phdr;
复制代码
 

前面已经提到,Program header table有多个entry,其实每个entry都是一个Elf32_Phdr类型数据结构,用这个数据结构可以找到每个Segment在文件中的位置,e_phentsize=sizeof(Elf32_Phdr),e_phnum=numof(Elf32_Phdr),每个Segment包含若干个section,只有对executable file和shared object file才能存在Program header。p_type指示当前Program header所指的Segment的类型,PT_NULL(0,指示无效的segment)/ PT_LOAD(1,指示当前Program header所指的Segment须加载到内存中执行)/ PT_DYNAMIC(2)/ PT_INTERP(3)/ PT_NOTE(4)/ PT_SHLIB(5)/ PT_PHDR(6)/PT_LOPROC(0x70000000)/PT_HIPROC(0x7fffffff)。p_offset指示Program header所指的Segment在文件中偏移量。p_vaddr指示Program header所指的Segment在内存中的虚拟地址。p_vaddr指示Program header所指的Segment在内存中的物理地址,一般可忽略。p_filesz指示Program header所指的Segment在文件中的大小。p_memsz指示Program header所指的Segment在内存中的大小,一般地,p_memsz>=p_filesz,对p_filesz不足的内存区域填0。

来源:http://www.cnblogs.com/brianhxh/archive/2009/07/04/1517020.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值