ELF文件详解

ELF文件详解

ELF(Executable and Linkable Format)可执行和可链接格式是一种对象文件格式,分为三种类型:

a.可重定位目标文件:包含了适合用来链接其他目标文件的代码和数据,从而创建出可执行或可共享的目标文件(文件后缀.o)
b.可执行目标文件:包含用于执行的程序,该文件规定了exec如何创建一个程序的进程映像(文件后缀可有可无)
c.共享目标文件:包含用来在两个上下文之间链接的代码和数据(文件后缀.so)

注:可重定位目标文件和共享目标文件用于程序链接,可执行目标文件用于程序执行
因为对于目标文件两种用途,因此目标文件的组织结构有两种:一种是用于链接的链接格式,另一种是用于执行的执行格式.

ELF文件格式

ELF文件有32位版本和64位版本,故其头文件结构也有32位结构和64位结构,分别定义为Elf32_Ehdr和Elf64_Ehdr.两种版本文件内容一样,只是有些成员的大小不一样.以下是32位版本的文件头结构Elf32_Ehdr.

数据类型说明:

名称大小对齐用途
Elf32_Addr44无符号程序地址
Elf32_Half22无符号中等大小整数
Elf32_Off44无符号文件偏移
Elf32_Sword44有符号大整数
Elf32_Word44无符号大整数
unsigned char11无符号小整数

1、ELF文件头 (Elf32_Ehdr 52个字节)

#define EI_NIDENT       16  
typedef struct elf32_hdr{  
	unsigned char e_ident[EI_NIDENT];   
	Elf32_Half    e_type;     /* file type */  
	Elf32_Half    e_machine;  /* architecture */  
	Elf32_Word 	  e_version;  
	Elf32_Addr    e_entry;    /* entry point */  
	Elf32_Off 	  e_phoff;        /* PH table offset */  
	Elf32_Off 	  e_shoff;        /* SH table offset */  
	Elf32_Word    e_flags;  
	Elf32_Half    e_ehsize;       /* ELF header size in bytes */  
	Elf32_Half    e_phentsize;    /* PH size */  
	Elf32_Half    e_phnum;        /* PH number */  
	Elf32_Half    e_shentsize;    /* SH size */  
	Elf32_Half    e_shnum;        /* SH number */  
	Elf32_Half    e_shstrndx; /* SH name string table index */  
} Elf32_Ehdr;
文件类型
/* Legal values for e_type (object file type).  */

#define ET_NONE     0       /* No file type */
#define ET_REL      1       /* Relocatable file */
#define ET_EXEC     2       /* Executable file */
#define ET_DYN      3       /* Shared object file */
#define ET_CORE     4       /* Core file */

2、Section Header (Elf32_Shdr 40个字节)

typedef struct {  
	Elf32_Word    sh_name;    /* name of section, index */  
	Elf32_Word    sh_type;      
	Elf32_Word    sh_flags;  
	Elf32_Addr    sh_addr;       /* memory address, if any */  
	Elf32_Off     sh_offset;  
	Elf32_Word    sh_size;        /* section size in file */  
	Elf32_Word    sh_link;  
	Elf32_Word    sh_info;  
	Elf32_Word    sh_addralign;  
	Elf32_Word    sh_entsize;     /* fixed entry size, if have */  
} Elf32_Shdr;  

/* Legal values for sh_flags (section flags).  */

#define SHF_WRITE        (1 << 0)   /* Writable */
#define SHF_ALLOC        (1 << 1)   /* Occupies memory during execution */
#define SHF_EXECINSTR        (1 << 2)   /* Executable */
#define SHF_MERGE        (1 << 4)   /* Might be merged */
#define SHF_STRINGS      (1 << 5)   /* Contains nul-terminated strings */


/* Legal values for sh_type (section type).  */

#define SHT_NULL      0     /* Section header table entry unused */
#define SHT_PROGBITS      1     /* Program data */
#define SHT_SYMTAB    2     /* Symbol table */
#define SHT_STRTAB    3     /* String table */
#define SHT_RELA      4     /* Relocation entries with addends */
#define SHT_HASH      5     /* Symbol hash table */
#define SHT_DYNAMIC   6     /* Dynamic linking information */
#define SHT_NOTE      7     /* Notes */
#define SHT_NOBITS    8     /* Program space with no data (bss) */
#define SHT_REL       9     /* Relocation entries, no addends */
#define SHT_SHLIB     10        /* Reserved */
#define SHT_DYNSYM    11        /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY    14        /* Array of constructors */
#define SHT_FINI_ARRAY    15        /* Array of destructors */
#define SHT_PREINIT_ARRAY 16        /* Array of pre-constructors */
#define SHT_GROUP     17        /* Section group */
#define SHT_SYMTAB_SHNDX  18        /* Extended section indeces */
#define SHT_NUM       19        /* Number of defined types.  */

3、Program Header (Elf32_Phdr 32个字节)

typedef struct elf32_phdr{  
	Elf32_Word    p_type;   
	Elf32_Off     p_offset;  
	Elf32_Addr    p_vaddr;        /* virtual address */  
	Elf32_Addr    p_paddr;        /* ignore */  
	Elf32_Word    p_filesz;       /* segment size in file */  
	Elf32_Word    p_memsz;        /* size in memory */  
	Elf32_Word    p_flags;  
	Elf32_Word    p_align;       
} Elf32_Phdr;  
 

4、Symbol Table (Elf32_Sym 16个字节 )

typedef struct elf32_sym{  
	Elf32_Word    st_name;  
	Elf32_Addr    st_value;  
	Elf32_Word    st_size;  
	unsigned char st_info;  
	unsigned char st_other;  
	Elf32_Half    st_shndx;  
} Elf32_Sym;  

符号类型和绑定信息(st_info) 该成员低4位表示符号的类型(Symbol Type),高28位表示符号绑定信息(Symbol Binding)

绑定信息

/* Legal values for ST_BIND subfield of st_info (symbol binding).  */


#define STB_LOCAL   0       /* Local symbol 局部符号,对于目标文件的外部不可见*/
#define STB_GLOBAL  1       /* Global symbol 全局符号,外部可见*/
#define STB_WEAK    2       /* Weak symbol 弱引用*/
#define STB_NUM     3       /* Number of defined types.  */
#define STB_LOOS    10      /* Start of OS-specific */
#define STB_GNU_UNIQUE  10      /* Unique symbol.  */
#define STB_HIOS    12      /* End of OS-specific */
#define STB_LOPROC  13      /* Start of processor-specific */
#define STB_HIPROC  15      /* End of processor-specific */

符号类型

/* Legal values for ST_TYPE subfield of st_info (symbol type).  */


#define STT_NOTYPE  0       /* Symbol type is unspecified 未知类型符号*/
#define STT_OBJECT  1       /* Symbol is a data object 该符号是个数据对象,比如变量、数组等*/
#define STT_FUNC    2       /* Symbol is a code object 该符号是个函数或其他可执行代码*/
#define STT_SECTION 3       /* Symbol associated with a section 该符号表示一个段,这种符号必须是STB_LOCAL的*/
#define STT_FILE    4       
/* Symbol's name is file name 该符号表示文件名,一般都是该目标文件所对应的源文件名,它一定是STB_LOCAL类型的,
并且它的st_shndx一定是SHN_ABS*/
#define STT_COMMON  5       /* Symbol is a common data object */
#define STT_TLS     6       /* Symbol is thread-local data object*/
#define STT_NUM     7       /* Number of defined types.  */
#define STT_LOOS    10      /* Start of OS-specific */
#define STT_GNU_IFUNC   10      /* Symbol is indirect code object */
#define STT_HIOS    12      /* End of OS-specific */
#define STT_LOPROC  13      /* Start of processor-specific */
#define STT_HIPROC  15      /* End of processor-specific */


#define SHN_UNDEF   0       
/* Undefined section
符号块未定义,在本目标文件被引用到,但是定义在其他目标文件中*/
#define SHN_ABS     0xfff1      
/* Associated symbol is absolute 
表示该符号包含了一个绝对的值。比如表示文件名的符号就属于这种类型的*/
#define SHN_COMMON  0xfff2  
/* Associated symbol is common 
表示该符号是一个“COMMON块”类型的符号,一般来说,未初始化的全局符号定义就是这种类型的
*/

readelf命令参考

readelf -a hello

nm命令还是比较简单而且强大的。以下是一些常见的符号类型

nm输出字符含义
RRead only symbol. 比如在代码中有一个const MAXDATA = 3095; 则MAXDATA就是一个Read only symbol
N这是一个调试符号
D这是一个已经初始化的变量的符号。比如代码中int i = 1和char *str = "Hello"则i和str都是这种类型的符号
TText段的符号。子程序都是这种符号,比如文件中实现了一个函数function,则function就是这种符号
U未定义的符号。如果文件中引用了不存在的函数,则这些未定义的函数符号就是这种类型
S未初始化的符号,比如全局变量int s;则s的符号就是此类型

Section

类型含义
.text已编译程序的机器代码
.rodata只读数据,如pintf和switch语句中的字符串和常量值
.data已初始化的全局变量
.bss未初始化的全局变量
.symtab符号表,存放在程序中被定义和引用的函数和全局变量的信息
.rel.text当链接器吧这个目标文件和其他文件结合时,.text节中的信息需修改
.rel.data被模块定义和引用的任何全局变量的信息
.debug一个调试符号表。
.line原始C程序的行号和.text节中机器指令之间的映射
.strtab一个字符串表,其内容包含.systab和.debug节中的符号表

ELF执行过程

Linux可执行文件类型的注册机制
为什么Linux可以运行ELF文件?
回答:内核对所支持的每种可执行的程序类型都有个struct linux_binfmt的数据结构

struct linux_binfmt {  
	 struct linux_binfmt * next;  
	 struct module *module;  
	 int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);  
	 int (*load_shlib)(struct file *)  
	 int (*core_dump)(long signr, struct pt_regs * regs, struct file * file);  
	 unsigned long min_coredump;     /* minimal dump size */  
	 int hasvdso;  
 };  

ELF中即为load_elf_binary

以我们的Hello World为例,gcc在编译时,除非显示的使用static标签,否则所有程序的链接都是动态链接的,也就是说需要解释器。由此可见,我们的Hello World程序在被内核加载到内存,内核跳到用户空间后并不是执行Hello World的,而是先把控制权交到用户空间的解释器,由解释器加载运行用户程序所需要的动态库(Hello World需要libc),然后控制权才会转移到用户程序

ELF文件中符号的动态解析过程

Global Offset Table(GOT)
在位置无关代码中,一般不能包含绝对虚拟地址(如共享库)

Procedure Linkage Table(PLT)
过程链接表(PLT)的作用就是将位置无关的函数调用转移到绝对地址

ELF文件加载和链接的简要总结

用户通过shell执行程序,shell通过exceve进入系统调用。(User-Mode)
sys_execve经过一系列过程,并最终通过ELF文件的处理函数load_elf_binary将用户程序和ELF解释器加载进内存,并将控制权交给解释器。(Kernel-Mode)
ELF解释器进行相关库的加载,并最终把控制权交给用户程序。由解释器处理用户程序运行过程中符号的动态解析

测试代码

/* hello.c */  
#include <stdio.h>  
  
int main()  
{  
    printf(“hello world!\n”);  
    return 0;  
}  

参考

ELF文件结构

你的变量究竟存在什么地方

文件加载机制

可执行文件(ELF)格式的理解

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骇客之技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值