首先要理清,切换用户是用命令su或者su -;与用户态进入内核态不是一回事。
大部分Linux发行版的默认账户是普通用户,而更改系统文件或者执行某些命令,需要root身份才能进行,这就需要从当前用户切换到root用户。Linux中切换用户的命令是su或su -。
su命令和su -命令最大的本质区别就是:前者只是切换了root身份,但Shell环境仍然是普通用户的Shell;而后者连用户和Shell环境一起切换成root身份了。只有切换了Shell环境才不会出现PATH环境变量错误。su切换成root用户以后,pwd一下,发现工作目录仍然是普通用户的工作目录;而用su -命令切换以后,工作目录变成root的工作目录了。用echo $PATH命令看一下su和su -以后的环境变量有何不同。以此类推,要从当前用户切换到其它用户也一样,应该使用su -命令。
如图所示:
用户空间:指的就是用户可以操作和访问的空间,这个空间通常存放我们用户自己写的数据等等;
而内核空间则是系统内核来操作的一块空间,这块空间里面存放系统内核的函数、接口等。
当一个程序运行时,如果它是在用户空间下执行,我们把此时运行得程序的这种状态成为用户态,而当这段程序执行在内核的空间执行时,这种状态称为内核态。
Linux严格意义上说的是一个操作系统,我们称之为“核心 "。但我们一般用户是不能直接使内核的,而是通过内核(kernel)的“外壳”程序,也就是说shell用于kernel沟通。
Shell是一种命令行解释器,它主要包含:1.将使用者的命令翻译给核心来处理。 2.将核心的处理结果翻译给使用者。
关于用户不能直接操作内核,其根本原因是为了对系统内核进行“保护”。
我们所说的用户态到内核态的切换,其实就是一个进程通过系统调用到内核的一些接口,从而实现切换。而该系统调用切换时通过软件中断来完成,该中断是程序人员自己开发出的一种正常的异常。
那么在Linux下,这个异常具体是调用int $0x80的汇编指令,这条汇编指令将产生向量为0x80的编程异常。
之所以系统调用需要借助这个中断异常来实现,是因为这个异常实际上就是通过系统门陷入内核。
(除了int 0x80外用户空间还可以通过int3——向量3、into——向量4 、bound——向量5等异常指令进入内核,而其他异常无法被用户空间程序利用,都是由系统使用的)
我们知道是先通过软件中断调用了0x80的这个编程异常,这个编程异常对应的是中断描述符表IDT中的第128项——也就是对应的系统门描述符。门描述符中含有一个预设的内核空间地址,它指向了系统调用处理程序:system_call()(别和系统调用服务程序混了)。
Linux一共有319个系统调用都从这里进入内核后,又该如何派发到它们到各自的服务程序去呢?
解决这个问题的方法很简单就是: 首先Linux为每个系统调用都进行了编号 (0—NR_syscall),同时在内核中保存了一张系统调用表 ,该表中保存了系统调用编号和其对应的服务例程,因此在系统调入通过系统门陷入内核前,(1)需要把系统调用号一并传入内核。在x86上,这个传递动作是通过在执行int0x80前,把调用号装入eax寄存器实现的。(2)系统调用处理程序一旦运行,就可以从eax中得到数据,(3)然后再去系统调用表中寻找相应服务例程了。如图:引用其他博主的知识。
除了需要传递系统调用号以外,许多系统调用还需要传递一些参数到内核,比如sys_write(unsigned int fd, const char * buf, size_t count)调用就需要传递文件描述符fd、要写入的内容buf、以及写入字节数count等几个内容到内核。碰到这种情况,Linux会有6个寄存器可被用来传递这些参数:eax (存放系统调用号)、 ebx、ecx、edx、esi及edi来存放这些额外的参数(以字母递增的顺序)。具体做法是在system_call( )中使用SAVE_ALL宏,把这些寄存器的值保存在内核态堆栈中。
做好上述工作之后,再执行系统调用处理程序,这样就从用户态切换到内核态。
本篇文章是学习其他人的博客,自己做整理。