LINUX内核研究----深入程序加载执行过程

程序的装载执行过程

从操作系统的角度来看一个程序最关键的特征是拥有独立的虚拟地址空间。

进程的建立:

程序启动时,操作系统会新建一个进程来执行该程序,主要分为三个步骤:

1、创建一个独立的虚拟地址空间,这一步的映射关系是从虚拟空间到物理内存的映射关系。

创建一个虚拟地址空间实际上并不是创建空间,而是内核中创建地址映射需要的数据结构。linux内核对虚拟地址空间进行抽象描述的数据结构是在用于虚存管理的mm_struct数据结构,而mm_struct数据结构又是在PCB中保存,故先在内核中分配两个页面的物理页,分别创建PCB和用于进程的内核栈空间,大小一共是8K。而在LINUX2.6内核后该PCB放在高速缓存中,之前存放PCB的地方用于存放thread_info结构体里面的成员指向高速缓存中的PCB信息。

同时分配一个页目录表,页的映射关系都是等到后面程序发生页错误由缺页异常处理程序来设置。

2.4之前的内核代码

LINUX内核研究----深入程序加载执行过程

2.6内核代码是:

LINUX内核研究----深入程序加载执行过程

            以上过程将由fork()系统调用函数完成:

2、读取可执行文件头,建立可执行文件各个段和虚拟地址空间中各个段的映射关系。

这一步做的是建立可执行文件和虚拟地址空间的映射关系,这种映射关系只是保存在内核中PCB中的一个数据结构。

ELF文件结构中有两个LOAD段,这两个LOAD段是ELF中的各种读写权限的相似的段合并。这一步地具体过程是将这两个LOAD段按页为单位分别映射到虚拟地址空间中的代码段和数据段。

 从ELF文件到虚拟地址空间的映射的这个过程使用的是mmap系统调用和execve()系统调用函数。

当程序运行时需要将可执行文件中的内容载入内存来执行,比如在进程访问某全局变量时,该全局变量还没有被载入内存,此时程序发生页错误时,操作系统才把该全局变量所对应的那个“缺页”从磁盘读取到真正的物理内存中,再设置虚拟页和物理页的映射关系。

从虚拟地址空间到物理地址映射通过多级页表映射方式

而操作系统捕获到缺页时需要知道当前缺少的页在可执行文件的哪个位置,这就是虚拟空间与可执行文件的映射关系。

由于可执行文件在装载时实际上是被映射的虚拟地址空间,所以可执行文件很多时候也是别称作映像文件。

 LINUX内核研究----深入程序加载执行过程

3、将CPU指令寄存器设置为当前可执行文件的入口(这个入口地址保存在ELF文件中),然后启动运行。执行的时候会不断的发生缺页中断,发生缺页中断时会将实际的可执行文件中的内容载入到物理内存中,然后建立虚拟内存页和物理内存页的映射关系。