4 ELF程序头

4 ELF程序头
foresta.yangELF程序头
程序头表提供了二进制文件的段视图,与节头表提供的节视图相反。早前讨论过的ELF二进制文件的节视图仅适用于静态链接。相比之下,下面我们将要讨论的是段视图。在将ELF二进制文件加载到进程并执行的时候,定位相关代码和数据并确定加载到虚拟内存中的内容时,操作系统和动态链接器就会用到段视图。
ELF段包含零个或多个节,实际上就是把多个节捆绑成单个块。段提供的可执行视图,只有ELF二进制文件会用到它们,而非二进制文件(如可重定位对象)则用不到它们。
程序头表使用Elf64_Phdr结构体类型的程序头对段视图进行编码,每个程序头均包含清单2-11所示的字段。

p_type字段
p_type字段标识了段的类型,该字段的重要类型包括PT_LOAD、PT_DYNAMIC及PT_INTERP。
-
PT_LOAD类型的段会在创建进程时加载到内存中,程序头的剩余部分描述了可加载块的大小和将其加载到的地址。
-
通常至少有两个PT_LOAD类型的段,一个包含不可写数据节,另一个包含可写数据节。
-
PT_INTERP类型的段包含了.interp节,该节提供了加载二进制文件的解释器的名称。
-
PT_DYNAMIC类型的段包含了.dynamic节,该节告诉解释器如何解析二进制文件用于执行。
p_flags字段
flag字段指定了段在运行时的访问权限,这里有3种重要的标志类型:PF_X、PF_W及PF_R。
- PF_X标志指定该段为可执行,并且可对代段设置该位(readelf在清单2-12中的Flg列将其显示为E而 非X)。
- PF_W标志表示该段为可写,并且一般只对可写数据段设置该位,而不对代码段设置该位。
- 最后,PF_R标志表示该段为可读,该属性在代码段和数据段都是正常情况。
p_offset、p_vaddr、p_paddr、p_filesz及 p_memsz字段
p_offset、p_vaddr及p_filesz字段类似于节头中的sh_offset、sh_addr及sh_size字段,它们分别指定了该段的起始文件偏移量、加载的虚拟地址以及段大小。对于可加载段,p_vaddr必须等于p_offset,以页面大小为模(通常为4096字节)。
tips:在某些操作系统上,可以使用p_addr字段来指定段在物理内存的哪个地址进行加载。在Linux操作系统中,该字段并未被使用且设置为零,因为操作系统在虚拟内存中执行二进制文件。
p_align字段
p_align字段类似于节头里的sh_addralign字段。该字段指定了 段所需的内存对齐方式(字节为单位),与sh_addralign一样,对齐 值0或1表示不需要特定的对齐方式。如果p_align未设置为0或1,则其 值必须是2的指数,并且p_vaddr必须等于p_offset模p_align。