ELF文件-段和程序头

可执行文件和共享目标文件(动态链接库)是程序在磁盘中的静态存储形式;要执行一个程序,系统就要先把相应的可执行文件和共享目标文件装载到进程的地址空间中,这样就形成一个可运行进程的内存空间布局,称为 进程镜像 ;一个已经装载完成的进程空间中会包含多个不同的 (Segment),比如,代码段、数据段、堆栈段,等等;
准备一个程序的内存镜像,大体上可以分为两个步骤: 装载 链接 ;前者是把目标文件装载到内存中,后者是解析目标文件中的符号引用;
一个可执行文件及其依赖的共享目标文件被完全成功地装载到进程的内存地址空间中之后,这个可执行文件或共享目标文件中的 程序头部表 (Program Header Table)就是必须存在的、不可缺少的必需品,程序头部表是一个数组,数组中的每一个元素就称为一个 程序头 (Program Header),每一个程序头描述一个 内存段 (Segment)或者一块用于准备执行程序的信息;内存中的一个目标文件中的段包含一个或多个 ;也就是ELF文件在磁盘中的一个或多个节可能会被映射到内存中的同一个段中;程序头只对可执行文件或共享目标文件有意义,对于其它类型的目标文件,该信息可以忽略;
在目标文件的ELF文件头部结构中,成员e_phentsize和e_phnum分别给出程序头部表中元素(程序头)的大小和数量;
程序头 使用结构体 Elf32_Phdr/Elf64_Phdr 来定义:
struct Elf32_Phdr
{
  Elf32_Word  p_type;   /* Segment type */
  Elf32_Off   p_offset; /* Segment file offset */
  Elf32_Addr  p_vaddr;  /* Segment virtual address */
  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 */
};
struct Elf64_Phdr
{
  Elf64_Word  p_type;   /* Segment type */
  Elf64_Word  p_flags;  /* Segment flags */
  Elf64_Off   p_offset; /* Segment file offset */
  Elf64_Addr  p_vaddr;  /* Segment virtual address */
  Elf64_Addr  p_paddr;  /* Segment physical address */
  Elf64_Xword p_filesz; /* Segment size in file */
  Elf64_Xword p_memsz;  /* Segment size in memory */
  Elf64_Xword p_align;  /* Segment alignment */
};
------字段详解------
1、 p_type :
该字段指明该程序头所描述的内存段的类型,或者如何解析该程序头的信息;取值如下:
PT_NULL    = 0: 该段没有被使用;
PT_LOAD    = 1: 该段是一个可装载的内存段;
PT_DYNAMIC = 2: 该段描述的是动态链接信息;
PT_INTERP     = 3: 该段描述的是一个以"\0"结尾的字符串,这个字符串是一个ELF解析器的路径;这种段类型只对可执行程序由意义,对其它类型的ELF文件无意义;在一个ELF文件中它最多只能出现一次,而且必须出现在其它可装载段的表项之前;
PT_NOTE    = 4: 该段描述一个以"\n"结尾的字符串,这个字符串包含一些附加的信息;
PT_SHLIB   = 5: 保留值;
PT_PHDR    = 6: 此类段如果存在的话,则它表示的是其自身所在的程序头部表在文件或内存中的位置和大小;这样的段在文件中可以不存在,只有当所在的程序头部表所覆盖的段只是整个程序的一部分时,才会出现一次这种表项,而且一定会出现在其它可装载段的表项之前;
PT_TLS     = 7: Thread-local storage segment;
PT_NUM     = 8: Number of defined types;
PT_LOOS    = 0x60000000 /* Start of OS-specific */
PT_GNU_EH_FRAME = 0x6474e550 /* GCC .eh_frame_hdr segment */
PT_GNU_STACK = 0x6474e551 /* Indicates stack executability */
PT_GNU_RELRO = 0x6474e552 /* Read-only after relocation */
PT_LOSUNW    = 0x6ffffffa
PT_SUNWBSS   = 0x6ffffffa /* Sun Specific segment */
PT_SUNWSTACK = 0x6ffffffb /* Stack segment */
PT_HISUNW    = 0x6fffffff
PT_HIOS      = 0x6fffffff /* End of OS-specific */
PT_LOPROC    = 0x70000000 /* Start of processor-specific */
PT_HIPROC    = 0x7fffffff /* End of processor-specific */
除非有特别要求,否则所有程序头的段类型字段p_type都是可选项,不是必须存在的;在所有程序头都不指定段类型的情况下,程序头部表中所有的表项都不代表任何特别的类型,而只是作为一种索引,表明其相应的段的大小和位置;

2、 p_offset :
该字段指明该段中内容在文件中的位置,即,段中内容的起始位置相对于文件开头处的偏移量;

3、 p_vaddr :
该字段指明该段中内容的起始位置在进程地址空间中的虚拟地址;

4、 p_paddr :
该字段指明该段中内容的起始位置在进程地址空间中的物理地址;对于目前大多数现代操作系统而言,应用程序中段的物理地址是不可预先得知的,所以,目前这个字段大多数情况下保留不用,或者被操作系统改作它用;

5、 p_filesz :
该字段指明该段中内容在文件中的大小,也可以是0;单位是字节;

6、 p_memsz :
该字段指明该段中内容在内存镜像中的大小,也可以是0;单位是字节;

7、 p_flags :
该字段指明该段中内容的属性;取值如下:
PF_X = (1 << 0) /* Segment is executable */
PF_W = (1 << 1) /* Segment is writable */
PF_R = (1 << 2) /* Segment is readable */
PF_MASKOS   = 0x0ff00000 /* OS-specific */
PF_MASKPROC = 0xf0000000 /* Processor-specific */

8、 p_align :
该字段指明该段中内容如何在内存和文件中对齐;对于可装载的段来说,其p_vaddr和p_offset的值至少要向内存页面大小对齐;如果值为0或1,则表明没有对齐要求,否则,p_align应该是一个正整数,并且是2的幂次数;p_vaddr和p_offset在对p_align取模后应该相等;

备注 :
p_type=PT_LOAD时,段的内容会被从文件中拷贝到内存中,如果p_memsz>p_filesz,则在内存中多出的存储空间中填0补充,即,段在内存中可以比在文件中占用更大空间;相反,p_filesz永远都不应该比p_memsz大,因为这样的话,在内存中就将无法完整地映射段的内容;在程序头部表中,所有PT_LOAD类型的程序头都按照p_vaddr的值做升序排列;
ELF文件(Executable and Linkable Format,可执行和可链接格式)是一种能够在不同操作系统上共享和执行的二进制文件格式。ELF文件部和程序头表ELF文件中的两个关键部分。 ELF文件部位于文件的开,包含了描述整个ELF文件的基本信息。具体包括标识字、目标机器体系结构、文件类型、入口点地址、程序头表偏移地址等重要信息。标识字用来识别文件ELF标志和版本。目标机器体系结构字标识了目标操作系统的硬件要求,例如x86、ARM等。文件类型字表示了ELF文件的类型,如可执行文件、共享目标文件、动态链接库等。入口点地址标识了程序运行的起始地址。程序头表偏移地址则指向ELF文件中的程序头表的位置, 程序头表包含了更加详细的信息。 程序头表位于ELF文件部之后,包含了多个描述ELF文件中各个(section)的表项。每个表项包含了的类型、文件中的偏移地址、内存中的虚拟地址、的大小等信息。ELF文件的基本组成单元,如代码、数据、bss。这些ELF文件中包含了可执行代码、全局变量、静态数据等。程序头表通过这些表项的信息告诉操作系统如何加载和运行ELF文件。 通过解析ELF文件部和程序头表,我们可以获取关于ELF文件的基本信息和的详细信息。这些信息对于调试、加载、执行ELF文件都非常重要。因此,深入理解ELF文件部和程序头表对于理解操作系统和二进制文件的运行机制具有重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值