首先在用户层面,bash进程会调用fork()系统调用创建一个新的进程,然后新的进程调用execve()系统调用执行指定的ELF文件,原先的bash进程继续返回等待刚才启动的新进程结束,然后继续等待用户输入命令
execve() 函数会调用到 do_execve()读取文件的前128个字节的目的是判断文件的格式,每种可执行文件的格式的开头几个字节都是很特殊的,特别是开头4个字节,常常被称做魔数(Magic Number),通过对魔数的判断可以确定文件的格式和类型
当do_execve()读取了这128个字节的文件头部之后,然后调用search_binary_handle()去搜索和匹配合适的可执行文件装载处理过程
ELF可执行文件的装载,是load_elf_binary()函数,步骤大致如下
(1)检查ELF可执行文件格式的有效性,比如魔数、程序头表中段(Segment)的数量。
(2)寻找动态链接的“.interp”段,设置动态链接器路径
(3)根据ELF可执行文件的程序头表的描述,对ELF文件进行映射,比如代码、数据、只读数据。
(4)初始化ELF进程环境,比如进程启动时EDX寄存器的地址应该是DT_FINI的地址
(5)将系统调用的返回地址修改成ELF可执行文件的入口点,这个入口点取决于程序的链接方式,对于静态链接的ELF可执行文件,这个程序入口就是ELF文件的文件头中e_entry所指的地址;对于动态链接的ELF可执行文件,程序入口点是动态链接器。
在系统开始运行时,动态链接器与普通共享对象一样被映射到了进程的地址空间,在主程序运行前,首先会把控制权交给动态链接器,由它完成所有的动态链接工作以后再把控制权交给主程序,然后开始执行