前言
一个本硕双非的小菜鸡,备战24年秋招,计划学习操作系统并完成6.0S81,加油!
本文总结自B站【哈工大】操作系统 李治军(全32讲)
老师课程讲的非常好,感谢
【哈工大】操作系统 李治军(全32讲)
内存使用与分段
程序需要放在内存中,程序需要在内存中取。取值执行程序,内存也就跟着使用了。
内存使用方法:将程序放入内存中,并让程序执行起来
如何把程序放入内存中并执行?
用磁盘将程序读到内存中
要想程序正常执行(这段例程),根据call40就必须要求main也要放在真实物理地址40处。程序要从0地址开始,一句一句放进去,然后pc=0开始取值执行。但有个问题:0地址并不是可供一个程序使用。
正确方法:应该是在内存中找一段空闲的内存,然后将这段程序放在这段空闲内存中。
解决:使用逻辑地址。修改程序中的内存地址的操作叫做重定位
什么时候完成重定位?
**1.编译时:**对于嵌入式系统可以在编译时完成重定位,但不灵活;
**2.载入时:**程序加载到内存的时候,比较灵活(非嵌入式系统一般都采用载入时进行重定位); 如程序从磁盘载入到内存时,程序中的内存地址(地址偏移量)统统加上程序所在基址;
重定位优缺点:
编译时重定位的程序只能放在内存固定位置(死板,编译时需要确定存放程序的空闲内存的基址);
载入时重定位的程序一旦载入内存就不能动了(灵活,载入时才确定存放程序的空闲内存的基址);
进程阻塞长时间不用,不能让他一直占用内存。使用交换机制
那么首先让一个程序编译好了,这个时候程序里面的都地址不需要修改,然后接下来让他执行需要创建进程(pcb)。那么需要在内存中找一段空闲的内存,然后把这个这段空闲的起始地址(基地址)找到并赋给PCB。然后把这段程序放到这一段空闲内存中,然后接下来在上下文切换的时候,基址就变成了基址寄存器,然后每执行一条指令的时候进行取值都要执行地址翻译(就是要取出一条地址,再拿PCB中的基址(基址寄存器中))那么一翻译就找到了你这条指令实际使用的物理内存的地址。
程序分段对于存储的好处(分段存储采用的是分治思想)
好处1:不是将整个程序放入内存,而是将各段分别放入内存,提高内存利用率;
好处2:在做swap时,不是把整个进程换入或换出,而是把进程的某个段换入或换出,提高了swap效率;且减少了swap次数;
好处3: 程序段或代码段是只读的;(变量集)数据段是可写的;分段存储可以避免代码被误写的场景;
每个进程也有自己的段表(用于存储程序多个段的基址)LDT表
可以把操作系统看作一个进程,操作系统对应的段表就是GDT表
进程一对应的段表就是LDT表
操作系统这个表放在gtd表里面,然后每个进程有自己的ldt表。那么在进程切换的时候ldt跟着切换,则在每次进行地址翻译的时候,根据ldt表里面来对应的基址、数据段和代码段找到程序中那个逻辑地址,所以完成了重定位过程就到物理地址可以去真正执行这条指令
在程序分段情况下使用内存的步骤;
步骤1:把程序分为多个段,包括代码段,数据段等;
步骤2:每个段在内存中找到一块空闲内存,并把这一段内存基址(起始地址)送入LDT表存储(如表1结构);LDT表就存储了该程序多个段的段基址;
步骤3:把LDT表赋值给对应进程的PCB; 至此程序已经被载入到内存中了;
最后:PC寄存器根据pcb设置初值,取指执行取指执行,在每执行一条指令的时候, 都查询LDT表找到段基址,并把该段基址加上地址偏移量得到物理内存地址,以进行后续的寻址操作;
补充: ldt表基址送入ldtr寄存器;