6.2. Linunx内核装载ELF过程

当用户输入一个命令执行一个ELF程序时,
首先在用户空间,bash调用fork()系统调用创建一个新的进程,
然后调用execve()执行指定的ELF文件,之前的bash进程返回等待才启动的新进程的结束。
在内核中,execve()对应的入口是sys_execve()定义在arch\i386\kernel\Process.c,sys_execve()进行一些参数的检查复制之后,调用do_execve()。do_execve()首先查找被执行的文件,读取文件的前128字节,判断文件的格式,然后调用search_binary_handle()取去搜索和匹配合适的可执行文件装载处理过程。
search_binary_handle()会通过判断文件头部的魔数确定文件的格式,并调用相应的装载处理过程。
比如ELF可执行文件的装载处理load_elf_binary().
a.out可执行文件的装载处理load_aout_binary().
脚本的装载处理load_script().
其中load_elf_binary()定义在fs/Binfmt_elf.c:
检查ELF可执行文件的有效性
寻找动态链接的.interp段,设置动态链接器路径
根据ELF可执行文件的程序头表的描述,对ELF文件进行映射
初始化ELF进程环境,比如进程启动时EDX寄存器的地址应该是DT_FINI的地址
将系统调用的返回地址改成ELF可执行文件的入口点,对于静态链接的ELF可执行文件,这个程序入口就是ELF文件中的e_entry,对于动态链接的ELF,程序入口点是动态链接器。
当load_elf_binary()执行完毕,返回至do_execve()再返回至sys_execve()时,已经把系统调用的返回地址改成了ELF程序入口地址。
所以sys_execve()系统调用从内核态返回到用户态时EIP寄存器直接跳转到了ELF程序的入口地址,于是新的程序开始执行,ELF可执行文件装载完成。