装载的两种方法
覆盖装入 : 利用程序的局部性原理,将一个程序中出现频率高的模块在程序运行时始终放入内存中,其他的模块,按照先后顺序,依次被覆盖。
如图例子:
mian部分在程序运行时始终占用内存,加入main()函数调用A函数,A函数读入内存,等到A执行结束,main调用b时,B把A所用的所有空间全部覆盖。
A和B是两个竞争模块。
被调用的模块被称作调用它的模块的子模块。
任何一个模块到根模块(这里是main())之间的路径叫做调用路径。
竞争模块和他们各自的的子模块之间禁止互相调用。
页映射:内存额磁盘所有数据和指令以页为单位进行装载或其它操作。利用覆盖,把使用频率小的页的内容进行替换。
如图例子:
一个程序有0-7,共8个页,但是只分0-3 4个物理页。加入虚拟页0真实在物理页2执行,虚拟页1真实在物理页0执行,虚拟页3在物理页1执行,虚拟页5也在物理页1执行,则虚拟页3和5会按照一定顺序对物理页1进行内容覆盖。
进程建立之前
进程很重要的特性:拥有独立的虚拟地址空间。
在进程装载相应的可执行文件并执行之前,需要做3件事情:
1 创建独立虚拟地址空间。这里并不是说真正创建了空间,而是创建了映射函数所需要的相应数据结构。
2 读取可执行文件头,建立虚拟空间和可执行文件之间的映射关系。这一步的用处:假如操作系统捕捉到了缺页错误,它需要知道程序所需要的页在可执行文件的具体位置。
3 cpu指令集存其摄制成可执行文件的入口,启动程序。
ELF可执行文件的划分
区分section 和segment.
section:从链接角度区分的,按照section,一个段一个段的存储。
segment:从装载角度,按照属性区分的,几个section是一个segment。
代码VMA:只读,可执行。
数据VMA:读写,可执行。
堆VMA:读写可执行。
栈VMA:读写,不可执行。
如果segment多且实际空间利用率低,则实际上映射过程建立时,会把各段接壤的部分共享一个物理页面,并把该页面分别映射两次。