系统调用的实现
前言
系统调用的直观实现
内核(用户)态,内核(用户)段
处理器保护环将其分为了四部分
对于内核段代码的处理用段寄存器来进行解决
硬件提供了“主动进入内核的方法”
系统调用的核心 int 0x80
拿Write函数举例
函数内部发生了什么
int 0x80中断的处理
中断处理程序
小结
前言
前面的文章说了什么是系统调用,就是系统提供给上层用户的一些函数,如open,read,write…,表面上是一些函数,背后是如何实现的呢? 这一篇文章就会记录系统调用是如何实现的。
系统调用的直观实现
反正所想要打印的代码与系统代码都在内存里,直接跳转,直接调用不可以吗? 答:肯定是不能的。 不能随意的调用内核的数据;不能随意的jmp。 如果能的话,操作系统内的很多重要的东西,比如root用户的密码,就不安全了。 所以系统调用就提供了一种可以进入内核的一种手段。
内核(用户)态,内核(用户)段
将内核程序和用户程序隔离!! 区分内核态和用户态:一种处理器“硬件设计”
处理器保护环将其分为了四部分
最内层0,为核心态。 中间两层1、2,为OS服务。 最外层3,为用户态。 当前程序执行在什么态(哪层环?)由于CS:IP是当前指令。所以用CS的最低两位来表示:0是内核态,3是用户态。 内核态可以访问任何数据,用户态不能访问内核数据。 对于指令跳转也一样,实现了隔离。
对于内核段代码的处理用段寄存器来进行解决
1. CPL(CS) 当前的特权级 current 取决于当前执行的什么指令
2. RPL(DS) 访问的数据段DS的最低两位
3. DPL 用来描述目标内存段的特权级 D目标 P特权 L级别 (DPL在GDT表中 可以找到)
4. DPL在GDT表中的级别都为0 意为内核段
5. 数字越大 特权级越低!! 只有当前的特权级>=要访问的mov的特权级,指令才可以jmp
硬件提供了“主动进入内核的方法”
对于Intel x86,那就是中断指令int int指令将使CS中的CPL改成0,“进入内核”
这是用户程序发起的调用内核代码的唯一方式。此时,CPL=3,而DPL=0。
系统调用的核心 int 0x80
(1)用户程序中包含一段包含int指令的代码 由谁做?库函数 (2)操作系统写中断处理函数,获取想调程序的编号 (3)操作系统根据编号执行相应代码
拿Write函数举例
函数内部发生了什么
在linux/include/unistd.h中
#define _syscall3(type,name,atype