Linux进程2——进程加载
Linux每个可执行程序都具有相同的虚拟地址分配,当OS启动进程时,是如何加载程序呢?
1. 进程结构体
每个进程都具有task_struct结构体,该结构体的mm字段负责对程序内存的虚拟地址映射。
mm中每个vm_area_struct对应可执行程序的段虚拟地址空间,例如.text等。当程序被执行时,程序的这些虚拟地址
就被填入不同的vm_area_struct中。
struct vm_area_struct { ... ... unsigned long vm_start; //虚拟地址开始地址 unsigned long vm_end; //虚拟地址结束地址 struct file * vm_file; //可执行程序文件句柄 unsigned long vm_pgoff; //段在可执行程序中位置 struct vm_operations_struct * vm_ops; //操作可执行程序的函数 ... ... };
2. 虚拟地址访问
Linux进程采用页机制访问虚拟地址。为了简化,可以这样理解,虚拟地址由3部分组成。
(1)高10bit表示页目录的基地址,保存在x86的CR3寄存器中。
(2)中间10bit是页索引,目录基地址加上该索引可以获取页的描述符地址。页描述中具有页实际物理地址。
(3)最后12bit为虚拟地址在物理页中偏置。
程序在访问虚拟地址时,有芯片硬件完成上面动作。
3.程序加载
为了保证程序运行时能够正常访问这些地址,必须在加载时填入页目录项,页索引和物理页。
(1)当程序加载时,由CR3寄存器获取页目录基地址pdg。
(2)访问虚拟地址,假定高10bit为i,中间10bit为j,最后12bit为k。首先读取页目录地址,判断pdg[i]是否为0,如果为0触发do_page_fault()分配一个物理页。
(3)pdg[i][j]为页描述符,修改描述,保存页物理地址。
(4)利用vm_area_struct 结构体中file,ops,pgoff等读取程序到内存。
4.页面交换
每个进程都是虚拟的4GB内存,如果物理不够怎么办?
每个物理页都具有mem_map结构体,该结构体记录如下信息:
(1)本页使用计数
(2)页年龄
(3)页帧号
对于数据映像,如果页没有被写过,可以直接丢掉;如果该页被修改,需要将“脏页”保存在交换文件中。