系统调用和库函数区别+用户态和内核态的转换

系统调用是系统提供给程序来操作硬件的一个接口。运行在内核态,一般来说可移植性不高,因为不同的操作系统有不同的系统调用。

库函数运行在用户态,虽然实现上也用到了系统调用,但是一般来说库函数都会通过缓冲等机制减少系统调用的次数,从而达到速度上的提高,而且它是与系统无关的,可移植性较高。

一般来说从用户态切换到内核态有三种方式:

一.是中断进入内核
二.是异常进入内核
三.是系统调用进入内核

在X86中调用int指令型系统调用后会把用户栈的%esp的值及相关寄存器压入内核栈中,系统调用通过iret指令返回,在返回之前会从内核栈弹出用户栈的%esp和寄存器的状态,然后进行恢复。所以在进入内核态之前要保存进程的上下文,中断结束后恢复进程上下文,那靠的就是内核栈。
  这里有个细节问题,就是要想在内核栈保存用户态的esp,eip等寄存器的值,首先得知道内核栈的栈指针,那在进入内核态之前,通过什么才能获得内核栈的栈指针呢?答案是:TSS(任务状态段)
X86体系结构中包括了一个特殊的段类型:任务状态段(TSS),用它来存放硬件上下文。TSS反映了CPU上的当前进程的特权级。
linux为每一个cpu提供一个tss段,并且在tr寄存器中保存该段。
在从用户态切换到内核态时,可以通过获取TSS段中的esp0来获取当前进程的内核栈 栈顶指针,从而可以保存用户态的cs,esp,eip等上下文。

总结在进程从用户态到内核态切换过程中,Linux主要做的事:

1:读取tr寄存器,访问TSS段

2:从TSS段中的sp0获取进程内核栈的栈顶指针

3: 由控制单元在内核栈中保存当前eflags,cs,ss,eip,esp寄存器的值。

4:由SAVE_ALL保存其寄存器的值到内核栈

5:把内核代码选择符写入CS寄存器,内核栈指针写入ESP寄存器,把内核入口点的线性地址写入EIP寄存器

此时,CPU已经切换到内核态,根据EIP中的值开始执行内核入口点的第一条指令。

关于用户态和内核态切换部分转载来源:http://www.cnblogs.com/justcxtoworld/p/3155741.html

猜你喜欢

转载自blog.csdn.net/qq_34262582/article/details/81105457
今日推荐