进程虚拟地址空间
Linux中,4GB的分配如下:
————————————————
Operating System
____________________________ 0xC000000(1GB)
User Process
———————————————— 0x00000000(4GB)
windows中,分别为2GB, 2GB.
装载的方式
1. 覆盖装入
这是在没有虚拟内存机制时的一种装载方式。
程序员需要手工将模块按照他们之间的调用依赖关系组织成树状结构。
2. 页映射
将虚拟内存和程序分页调度。
有FIFO(先进先出)算法, LUR(最少使用)算法。
装载的过程
1. 进程的建立
一,创建一个独立的虚拟地址空间。
一个虚拟空间有一组页映射函数将虚拟空间的各个页映射至相应的物理空间,创建要一个虚拟空间实际上并不是创建空间,而是创建映射函数所需要要的相应的数据结构。
二,读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系。
虚拟空间中的一个段叫做虚拟内存区域(VMA, Virtual Memory Area): 记录对应在ELF文件中的偏移等。
三,将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。
2. 页错误(Page Fault)
当CPU开始打算执行这个地址的指令时,发现是个空页面,于是产生一个页错误。
CPU将控制权交给操作系统,操作系统调用页错误例程来处理这种错误。
操作系统查询第二步中建立的数据结构,然后找到空页面所在的VMA,计算出相应的页面在可执行文件中的偏移,然后在物理内存中分配一个物理页面,将进程中该虚拟页与分配的物理页之间建立映射关系,然后把控制权再还回进程,进程从刚才页错误的位置再重新开始执行。
进程的虚拟内存空间分布
1. ELF文件的链接视图何执行视图
从Segment来看,ELF文件就是执行视图,从Section来看,ELF文件就是链接视图。
ELF可执行文件有一个数据结构叫程序头表(Program Header Table)用来保存Segment信息,因为ELF目标文件不需要被装载,所以它没有。
typedef struct {
Elf32_Word p_type; //Segment的类型
Elf32_Off p_offset; //Segment在文件中的偏移
Elf32_Addr p_vaddr; //Segment的第一个字节在虚拟地址空间中的起始位置
Elf32_Addr p_paddr; //Segment的物理装载地址
Elf32_Word p_filesz; //Semgent在ELF文件中所占空间长度
Elf32_Word p_memsz; //Segment在进程虚拟地址空间中所占用的长度
Elf32_Word p_flags; //权限标志
Elf32_Word p_align; //对齐属性
}Elf32_Phdr;
2. 堆和栈
他们也是以VMA的形式存在的
3. 进程栈的初始化
进程刚开始启动的时候,需知道一些进程运行的环境,最基本的就是系统环境变量何进程的运行参数。在进程启动前将这些信息提前保存代进程的虚拟空间的栈中(VMA的Stack VMA中)。