1.3.1.CPU的运行模式:内核模式和用户模式
- 特权指令:有少数指令是为编制系统管理程序专门设置的,只有操作系统才能使用。如果用户误用这些特权指令,称为非法指令,将引发故障中断。
① 有关 I/O 的指令。
② 访问程序状态字寄存器(PSW)的指令。
③ 存取特殊寄存器(如用于内存保护的寄存器)的指令。
④ 其他访问系统状态和直接访问系统资源的指令等 - 内核模式:指操作系统管理程序运行的状态,具有较高的特权级别,又称为特权态、系统态,内核态或管态
- 用户模式:指用户程序运行时的状态,具有较低的特权级别,又称为普通态、用户态或目态。
- 管态:程序执行时可以使用特权指令。执行系统管理程序,特权态、系统态、内核态、核心态。
- 目态:程序执行时不可使用特权指令,I/O 指令、时钟设置、中断机制、系统管理等,是用户程序运行时的状态,较低的特权级别,普通态(普态)、用户态。
- 注意:访管指令不是特权指令。用户从用户态进入内核态必定通过访管指令。从内核态返回用户态可以修改状态字实现。
- CPU状态如何转变?
- 核心态到用户态 --修改 PSW
- 用户态到核心态 --用户不能修改 PSW --系统调用 --访管指令(陷入指令,trap)
① 通过中断实现从用户态到核心态的改变。
② 在核心态下由操作系统代替用户完成其请求(指定的操作)。
③ 操作系统完成指定操作后再通过修改程序状态字(PSW)由核心态切换回用户态
1.3.2.异常与中断
- 中断:是指程序执行过程中,当发生某个事件时,中止 CPU 上现行程序的运行,引出处理该事件的程序执行的过程。
- 按照中断信号的来源,可把中断分为:
① 外中断(又称中断)指来自处理器和主存之外的中断。电源故障中断,时钟中断,控制台中断,I/O中断等,不同的中断具有不同的中断优先级,处理高一级中断时,往往会屏蔽部分或全部低级中断
② 内中断(又称异常)指来自处理器和主存内部的中断。通路校验错,主存奇偶错,非法操作码,地址越界,页面失效(缺页异常),调试指令,访管中断,算术操作溢出等各种程序性中断,不能被屏蔽,一旦出现立即响应并处理
- 按照中断信号的来源,可把中断分为:
- 中断和异常的区别:中断是由与现行指令无关的中断信号触发的(异步的),且中断的发生与 CPU 处在用户模式或内核模式无关,在两条机器指令之间才可响应中断,一般来说,中断处理程序提供的服务不是为当前进程所需的,如时钟中断、硬盘读写服务请求中断;异常是由处理器正在执行现行指令而引起的,一条指令执行期间允许响应异常,异常处理程序提供的服务是为当前进程所用的。异常包括很多方面,有出错(fault),有陷入(trap),有终止。
- 出错和陷入的区别如下:
① 它们发生时保存的返回指令地址不同,出错保存指向触发异常的那条指令,而陷入保存指向触发异常的那条指令的下一条指令。
② 从异常返回时,出错会重新执行那条指令,而陷入就不会重新执行那条指令。缺页异常是一种出错,陷入主要应用在调试中。 - 中断处理程序:它的主要任务是处理中断事件和恢复正常操作。不同中断源对应不同中断处理程序,故快速找到中断处理程序的入口地址是一个关键问题。
- 中断处理程序主要做四项工作:
① 保护未被硬件保护的一些必需的处理状态(现场保护)。
② 识别各个中断源,分析产生中断的原因。
③ 处理发生的中断事件。
④ 恢复正常操作(现场恢复)。
- 中断处理程序主要做四项工作:
1.3.3.系统调用
- 操作系统内核中设置了一组用于实现系统功能的子程序,当用户程序在用户态执行中需要系统提供服务时能使用这组子程序
- 系统调用的处理过程:
① 当系统调用发生时,处理器通过一种特殊的机制,通常是中断或者异常处理,把控制流程转移到监控程序内的一些特定的位置。同时,处理器模式转变成特权模式。
② 由监控程序执行被请求的功能代码。这个功能代码代表着对一段标准程序段的执行,用以完成所请求的功能。
③ 处理结束之后,监控程序恢复系统调用之前的现场;把运行模式从特权模式恢复成为用户方式;最后将控制权转移回原来的用户程序。 - 系统调用的复杂性
① 现代操作系统除了提供直接使用系统调用指令的接口外,通常的做法是提供一套方便,实用的应用程序库函数(应用程序设计接口-API)
② API不一定都是系统调用(尽管表面类似)
③ 系统调用一定需要调用访管指令(陷入)进入到内核态
1.3.4.程序的链接和装入
- 多道程序环境下,程序要运行必须为之创建进程,而创建进程的第一件事就是分配内存称为装入(加载)
- 源程序要运行通常经过编译,链接,装入等几个步骤
① 编译:由编译程序(Compiler)对用户源程序进行编译,形成若干个目标模块(ObjectModule),c程序编译完成,形成.o文件,每个.o文件称为独立的逻辑空间,其内含有逻辑地址;
② 链接:由链接程序(Linker)将编译后形成的一组目标模块以及它们所需要的库函数链接在一起,形成一个完整的装入模块(Load Module),把库函数具体实现,装入exe文件,其内是逻辑地址;
③ 装入:由装入程序(Loader)将装入模块装入内存,.exe由若干个.o文件链接形成。- 程序的装入
① 绝对装入方式(Absolute Loading Mode):事先确定了程序驻留在内存的绝对地址,装入模块被装入内存后,由于程序中的逻辑地址和实际内存地址完全相同,不需要对程序和数据的地址进行修改
②可重定位装入方式(Relocation Loading Mode):装入时对目标程序中指令和数据地址进行修改为物理实地址的过程称为重定位装入,地址变换通常一次性完成,以后不在改变,称为静态重定位
③动态运行时的装入方式(Dynamic Run-time Loading):把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝地地址,地址转换推迟到真正运行时,因此装入内存后所有地址仍为相对地址 - 程序的链接
① 静态链接(Static Linking)方式
② 装入时动态链接(Load-time Dynamic Linking)
③ 运行时动态链接(Run-time Dynamic Linking)
- 程序的装入
1.3.5.程序运行时内存映像与地址空间
- 装载到内存中的程序代码区域称为程序的内存映像,其按存放的内容可以分为3个区。
① 程序区:存放程序指令的区域。
② 静态存储区:存放永久数据区域。
③ 动态存储区:存放临时数据的区域。 - 一个由 C/C++编译的程序的内存分布分为以下几个部分:
① 栈(stack):也是我们所说的堆栈,是由编译器自动分配释放,用来存放函数参数值,函数的返回地址,非静态局部变量的值等。其操作方式类似于数据结构中的栈(后进先出LIFO)。
② 堆(Heep):一般由程序员分配释放,若程序员不释放,程序结束可能由OS回收。
③ 全局区(静态区):全局变量和静态变量存储在这一块,初始化的全局变量河静态变量放在一块区域,未初始化的全局变量静态变量放在相邻的另一块区域(BSS)。程序结束后由系统释放。
④ 文字常量区:常量字符串放在这个区域。
⑤ 程序代码区:存放函数体的二进制代码。