p_offset: 该segment的数据在文件中的偏移地址(相对文件头)p_vaddr: segment数据应该加载到进程的虚拟地址p_paddr: segment数据应该加载到进程的物理地址(如果对应系统使用的是物理地址)p_filesz: 该segment数据在文件中的大小p_memsz: 该segment数据在进程内存中的大小 。注意需要满足 p_memsz>=p_filesz ,多出的部分初始化为0,通常作为 .bss 段内容p_flags: 进程中该segment的权限(R/W/X)p_align: 该segment数据的对齐,2的整数次幂 。即要求 p_offset % p_align = p_vaddr。剩下的 p_type 字段,表示该program segment的类型,主要有以下几种:
PT_NULL: 表示该段未使用PT_LOAD: Loadable Segment , 将文件中的segment内容映射到进程内存中对应的地址上 。值得一提的是SPEC中说在program header中的多个PT_LOAD地址是按照虚拟地址递增排序的 。PT_DYNAMIC: 动态链接中用到的段,通常是RW映射,因为需要由 interpreter (ld.so)修复对应的的入口PT_INTERP: 包含interpreter的路径,见下文PT_HDR: 表示program header table本身 。如果有这个segment的话,必须要在所有可加载的segment之前,并且在文件中不能出现超过 一次。在不同的操作系统中还可能有一些拓展的类型,比如 PT_GNU_STACK 、 PT_GNU_RELRO 等 , 不一而足 。
小结至此,ELF文件中相关的字段已经介绍完毕,主要组成也就是Section Header Table和Program Header Table两部分,整体框架相当简洁 。而ELF中体现拓展性的地方则是在Section和Segment的类型上(s_type和p_type),这两个字段的类型都是 ElfN_Word ,在32位系统下大小为4字节,也就是说最多可以支持高达 2^32 - 1 种不同的类型!除了上面介绍的常见类型,不同操作系统或者厂商还能定义自己的类型去实现更多复杂的功能 。
程序加载在新版的ELF标准文档中 , 将ELF的介绍分成了三部分,第一部分介绍ELF文件本身的结构,第二部分是处理器相关的内容,第三部分是操作系统相关的内容 。ELF的加载实际上是与操作系统相关的,不过大部分情况下我们都是在GNU/Linux环境中运行,因此就以此为例介绍程序的加载流程 。
Linux中分为用户态和内核态,执行ELF文件在用户态的表现就是执行 execve 系统调用,随后陷入内核进行处理 。
内核空间内核空间对execve的处理其实可以单独用一篇文章去介绍 , 其中涉及到进程的创建、文件资源的处理以及进程权限的设置等等 。我们这里主要关注其中ELF处理相关的部分即可,实际上内核可以识别多种类型的可执行文件 , ELF的处理代码主要在 fs/binfmt_elf.c 中的 load_elf_binary 函数中 。
对于ELF而言,Linux内核所关心的只有Program Header部分 , 甚至大部分情况下只关心三种类型的Header,即 PT_LOAD 、 PT_INTERP 和 PT_GNU_STACK。以3.18内核为例,load_elf_binary主要有下面操作:
对ELF文件做一些基本检查,保证 e_phentsize = sizeof(struct elf_phdr) 并且 e_phnum 的个数在一定范围内;循环查看每一项program header , 如果有PT_INTERP则使用 open_exec 加载进来,并替换原程序的 bprm->buf ;根据 PT_GNU_STACK 段中的flag设置栈是否可执行;使用 flush_old_exec 来更新当前可执行文件的所有引用;使用 setup_new_exec 设置新的可执行文件在内核中的状态;setup_arg_pages 在栈上设置程序调用参数的内存页;循环每一项 PT_LOAD 类型的段,elf_map 映射到对应内存页中 , 初始化BSS;如果存在interpreter,将入口(elf_entry)设置为interpreter的函数入口,否则设置为原ELF的入口地址;install_exec_creds(bprm) 设置进程权限等信息;create_elf_tables 添加需要的信息到程序的栈中,比如 ELF auxiliary vector ;设置 current->mm 对应的字段;从内核的处理流程上来看,如果是静态链接的程序,实际上内核返回用户空间执行的就是该程序的入口地址代码;如果是动态链接的程序 , 内核返回用户空间执行的则是interpreter的代码,并由其加载实际的ELF程序去执行 。
推荐阅读
- ox是什么意思 ox是什么意思英语
- 梦到佛庙 梦到佛庙是什么征兆佛庙
- 梦到死去的陌生人 梦到死去的陌生人是什么意思
- 梦到水潭没水 梦到水潭没水什么意思
- 梦到水潭里好多鱼 梦到水潭里好多鱼什么意思
- 翡翠梅花的寓意是什么,翡翠花的寓意和象征
- 梦到水潭里洗衣服 梦到水潭里洗衣服什么意思
- 睡觉梦到鬼 睡觉梦到鬼是什么预兆
- 梦到在水潭里走动 梦到在水潭里走动什么意思
- 梦到水潭玩水 梦到水潭玩水什么意思