当前位置: 首页 > article >正文

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)格式的理解

http://www.lryc.cn/news/2420157.html

相关文章:

  • 新手安装 Ubuntu 操作系统步骤教程
  • SOTA:目标识别、计算机视觉中常见的名词SOTA的意思
  • Unicode及UTF-8、UTF-16、UTF-32
  • x86_64和AMD64和ARM64?傻傻分不清楚?
  • 保姆式介绍DDR5(比喻方法讲解)
  • 什么是VOIP-网络电话名词详解
  • 最全.NET Core各个版本特性整理,面试可能会考
  • iso文件打开方法
  • JDK版本说明/下载安装/环境配置 全过程详解
  • linux中fd的几点理解——一切皆文件
  • 《漏洞研究》Apache Log4j2 远程代码执行漏洞_apache log4j2远程代码执行漏洞
  • beyond compare简易破解方法
  • 【编程实践】Google Guava 极简教程
  • 知识点 | 今天好好学习MPP和MapReduce分别是个嘛?!
  • 微信小程序框架weui的基础使用
  • 带你正确认识Unicode和UTF-8
  • EIP的理解
  • C语言MD5算法
  • 从零学MyCat(一)Mycat基本介绍及安装
  • [HPC入门] 高性能计算 (HPC) 是什么?哪些业务场景需要HPC?
  • JPA Spring Data JPA详解
  • 一文弄懂 Unicode 编码
  • 字符串 格式化 String.format()的详细解释
  • 【计算机网络】localhost不能访问,127.0.0.1可以访问?
  • win10自动更新关闭
  • Fiverr 攻略:跨境自由职业通过 Fiverr 盈利
  • freemark--模版引擎
  • Java——反射(reflection)详解
  • SSM基于协同过滤推荐算法的新闻推荐系统43149
  • Hibernate—(搭建、简单使用)