Linux操作系统分析之进程的创建与可执行程序的加载

                                              SA****6343  孙洪菠

 

对进程的创建与可执行程序的加载总结如下:

  linux系统通过函数fork( )exec()来创建一个新的进程,更确切的说,这两个函数是分别用于进程的创建和进程修改,函数fork( )用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;函数族exec( )用来启动另外的进程以取代当前运行的进程。

 

一、进程的创建过程:

  Linux中创建进程的调用fork实际上是调用do_fork(),do_fork在做一些预处理之后,实际上是调用copy_process()函数复制进程。copy_process首先申请了一个新的task_struct,然后调用了dup_task_struct()拷贝父进程的进程描述符。之后,对新进程的描述符中的数据结构进行初始化,比如设置did_exec,irq_events等。接着,将父进程的资源进行逐一拷贝,这些资源包括:打开的文件,IO,内存信息,线程信息等。在为子进程分配pid之后,将其加入到进程队列中。之后在do_fork中将子进程wake_up_new_task()。

  执行过fork( )函数后,子进程作为父进程的一个拷贝,与父进程使用相同的代码段,复制父进程的堆栈段和数据段。子进程不在于父进程共享数据,子进程自己修改数据后自然不会对父进程的数据造成影响。对于区分父进程和子进程,是通过不同的进程号来实现的。对父进程而言,它的进程号是由比它更低层的系统调用赋予的,而对于子进程而言,它的进程号即是fork函数对父进程的返回值。

 

二、可执行程序的加载过程:

  通过总结可以得到,在进入execve系统调用之后,Linux内核就开始进行真正的装载工作。在内核中,execve()系统调用相应的入口是sys_execve(),它被定义在arch/x86/kernel/exec.c中。sys_execve()进行一些参数检查复制之后,调用do_execve()。do_execve会首先查找被执行的文件,如果找打文件。则读取文件的前128个字节以确定被检查的文件的格式。然后,继续调用search_binary_handle()去搜索合适的可执行文件装载处理过程。比如ELF可执行文件的装载处理工程是load_elf_binary()。他的主要步骤是:检查elf文件的有效性,寻找动态链接库的“.interp”段,设置动态链接器的路径,根据ELF的可执行文件的程序头表的描述,对ELF文件进行映射,比如代码、数据、只读数据,初始化ELF进程环境。将系统调用的返回地址修改为ELF可执行文件的入口点。在设置了eip之后,sys_execve返回到用户态时,程序就返回到新的程序开始执行,ELF可执行文件装载完成。

  进程调用过exec( )函数族后,进程的代码段会被替换成新的程序的代码,原有的堆栈段和数据段也会被废弃,开辟新的数据段和堆栈段。唯一留下的是进程号。这样一个新的进程就创建成功。

 

附件:  Linux内核之进程和系统调用

原文地址:https://www.cnblogs.com/SA226343/p/3109441.html