2024.06.25:操作系统过程调用与系统调用学习笔记
第5节 过程调用与系统调用
- 5.1 过程调用/函数调用/子程序调用
- 5.2 系统调用
- 5.2.1 系统调用汇编层
- 5.3 过程调用与系统调用的对比
5.1 过程调用/函数调用/子程序调用
(过程调用)也称为(函数调用)或(子程序调用),它允许程序代码被组织成(块),每个块完成特定的任务,这些块可以在程序的多个地方调用。
过程调用既然是调用,那就一定会有一个(过程P:调用者caller)和一个(过程Q:被调用者callee)
过程调用可以简单归纳总结成6步:
- P将入口参数放在Q能访问的到的地方
第一次:此时,P这里指的是main函数,Q指的是caller函数,如果被调用的这个函数Q是有参数的,那参数到底传给谁,是由调用者的函数决定的,因此调用者的函数应当将这个参数放在被调用的这个函数可以访问到的地方
第二次:caller函数应该把add需要用到的这些参数放到add函数可以访问到的地方,这个参数的值还是压到caller的栈帧中,注意add函数看似不访问caller的局部变量区,实际上它还是会有一些区域是这个add函数可以访问到的,它会被叫作(参数调用区)。我们现在会通过两个寄存器的中转,把这两个局部变量先复制到这两个寄存器中,然后再压回到caller的栈帧中(圈起来的区域是局部变量区,蓝色区域是参数调用区)
- P将返回地址存到特定的地方,然后将控制转移到Q
第一次:假设调用caller()函数的过程是main(),caller()函数没有参数,所以直接保存main函数的返回地址,控制转移到caller()
第二次:
- Q保存P的现场,并为自己的非静态局部变量分配空间
- 被调用者caller应该去保存调用它的函数main函数它的现场,由于这个代码里面没有体现main函数,所以就不去考虑这个。
- Q,也就是caller函数应该为自己的非静态局部变量去分配空间,比如这里的temp1,temp2,sum等
- 执行Q的过程体
现在add这个函数的起始地址改到PC里面,这样我们就可以根据PC去执行add这个函数,add函数内部并没有什么含金量,就是直接去返回一个两个参数的求和,规定这个值一定会放在EAX这个寄存器中,通过中转把EAX这个结果写回到caller的栈帧中局部变量sum的这个位置
- Q恢复P的现场,并释放局部变量所占空间
add函数执行完之后会将结果放到EAX寄存器再复制到栈里面去,此时add函数调用已经结束了,然后add函数会执行ret指令,ret指令会做两件事情,首先它会让栈帧里面的这个返回地址出栈,出栈之后,返回地址弹出这个值写回PC里面,PC带领CPU回到caller函数,也就相当于caller的栈帧被清理了
- Q取出返回地址,将控制转移到P
主存里面有一个区域叫作堆栈(一个堆区、一个栈区),对于(栈)来说,它的特性就是从高地址往低地址去增长的,并且它满足数据结构我们学过的这个栈的特性(先进后出)
5.2 系统调用
系统调用的引用是因为用户程序想要去申请操作系统它的服务,操作系统的核心服务放在操作系统的内核部分,而操作系统内核常驻在内存的某一个区域中。
比如说你的一个用户进程想要去读写某个文件,这个用户进程其实是没有权限去执行这个指令的,关于所有的文件管理它都是由内核去进行的,所以此时必须要专区执行内核的代码。
但是我们知道CPU有两种工作状态,在用户态下去执行用户程序的时候,是没有办法去访问到操作系统的内核去代码,此时我们就需要CPU转到内核态,从而它就可以去访问到操作系统内核的代码,完成我们想要的操作,这个就是系统调用。
系统调用既然需要CPU变态,那它就需要通过一个软中断指令,这个软中断并不会显示地出现在用户程序里
5.2.1 系统调用汇编层
5.3 过程调用与系统调用的对比
- 过程调用没有引发中断,而系统调用是通过发起一个软中断实现调用OS内核代码的
- 过程调用在调用时只需要保存PC而不需要保存PSW,而系统调用需要正常地进行(内部)中断处理,因此需要保存PC和PSW
- 过程调用全程CPU都处于同一个工作模式,即用户态或内核态,而系统调用会导致CPU从用户态切换内核态
- 过程调用的被调用函数会出现在代码中,而系统调用一个库函数即可实现,操作系统内核的代码不会出现在程序代码中
- 过程调用通过CALL或JMP指令进入,而系统调用通过INT或TRAP指令进入
- 过程调用是可以嵌套的,而系统调用一般不允许发生嵌套或递归