linux中ELF格式二进制程序

0. 简介 
在linux系统的可执行文件(ELF文件)中,开头是一个文件头,用来描述程序的布局,整个文件的属性等信息,包括文件是否可执行、静态还是动态链接及入口地址等信息;如下图所示:?

linux中ELF格式二进制程序

文章插图
 
程序文件中包含了程序头,程序的入口地址等信息不需要写死,调用代码可以通用,根据实际情况加载;此时的文件不是纯碎的二进制可执行文件了,因为包含的程序头不是可执行代码;将这种包含程序头的文件读入到内存后,从程序头中读取入口地址,跳转到入口地址执行;
 
0.1 文件格式 
linux系统中用C语言编写完代码,使用编译器gcc编译生成的是ELF格式的二进制文件;
ELF指:Executable and Linkable Format,可执行链接格式;本文中的目标文件指各种类型符合ELF规范的文件,如:二进制可执行文件、Linux下的.o目标文件和.so动态库文件;
可执行文件(Executable file):经过编译链接后,可以直接运行的程序文件;
共享目标文件(Shared object file):动态链接库,在可执行文件被加载的过程中动态链接,成为程序代码的一部分;
可重定位文件(Relocatable file):可重定位文件即目标文件,是源文件编译后但未完成链接的半成品,被用于与其他目标文件合并链接,以构建出二进制可执行文件或动态链接库;
核心转储文件(Core dump file):当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些信息转储到核心转储文件;
 
0.2 段和节 
程序中的段(Segment)和节(Secton)是真正的程序体;段包括代码段和数据段等,段是由节组成的,多个节经过链接后被合并为一个段;
段和节的信息用header描述,程序头是program header,节头是section header;段和节的大小和数量都是不固定的,需要用专门的数据结构来描述,即程序头表(program header table)和节头表(section header table),这是两个数组,元素分别是程序头(program header)和节头(section header);程序头表(program header table)中的元素全是程序头(program header),节头表(section header table)中的元素全是节头(section header);程序头表是用来描述段(Segment)的,成为段头表;段是程序本身的组成部分;
由于段和节的大小和数量都是不固定的,程序头表和节头表的大小也不固定,两个表在程序文件中的位置也不固定;需要在一个固定的位置,用一个固定大小的数据结构来描述程序头表和节头表的大小和位置信息,即位于文件最开始部分的ELF header;
 
1. ELF header 
ELF文件分为文件头和文件体两部分;先用ELF header从文件全局概要出程序中程序头表、节头表的位置和大小等信息;然后从程序头表和节头表中分别解析出各个段和节的位置和大小等信息;
可执行文件和待重定位文件,文件最开头的部分是ELF header;程序头表对于可执行文件是必须的,而对于待重定位文件是可选的;
ELF文件头用Elf32_Ehdr和Elf64_Ehdr结构体表示;
// include/uapi/linux/elf.h#define EI_NIDENT   16typedef struct elf32_hdr{  unsigned char e_ident[EI_NIDENT];  Elf32_Half    e_type;  Elf32_Half    e_machine;  Elf32_word    e_version;  Elf32_Addr    e_entry;  /* Entry point */  Elf32_Off e_phoff;  Elf32_Off e_shoff;  Elf32_Word    e_flags;  Elf32_Half    e_ehsize;  Elf32_Half    e_phentsize;  Elf32_Half    e_phnum;  Elf32_Half    e_shentsize;  Elf32_Half    e_shnum;  Elf32_Half    e_shstrndx;} Elf32_Ehdr;typedef struct elf64_hdr {  unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */  Elf64_Half e_type;  Elf64_Half e_machine;  Elf64_Word e_version;  Elf64_Addr e_entry;       /* Entry point virtual address */  Elf64_Off e_phoff;        /* Program header table file offset */  Elf64_Off e_shoff;        /* Section header table file offset */  Elf64_Word e_flags;  Elf64_Half e_ehsize;  Elf64_Half e_phentsize;  Elf64_Half e_phnum;  Elf64_Half e_shentsize;  Elf64_Half e_shnum;  Elf64_Half e_shstrndx;} Elf64_Ehdr;
linux中ELF格式二进制程序

文章插图
 
e_ident[EI_NIDENT]是16字节大小的数组,用来表示ELF字符等信息,开头四个字节是固定不变的elf文件魔数,0x7f 0x45 0x4c 0x46;


推荐阅读