详谈操作系统中的内核态和用户态

2023-09-17 22:16:56

不知道大家有没有思考过这样一个问题:什么是处理器(CPU)的状态?🤔

其实CPU和人一样,没有执行程序的时候,是没有什么状态的,当它执行的程序是用户程序的时候就叫用户态,当执行的程序是操作系统的代码时就叫系统态或者内核态.

接下来,我们就来谈谈内核态和用户态.

目录

1.内核态和用户态的概念 

2.内核态和用户态的区别

3.特权指令和非特权指令 

这是一个最简单的HelloWorld程序


1.内核态和用户态的概念 

内核态:可以访问所有的硬件设备,也可以执行硬件上能够运行的各种指令

用户态:只能执行一部分机器指令,不可以运行I/O命令或者影响机器控制的命令

 操作系统是运行在内核态的,而操作系统提供的用户接口程序和支持的应用程序,是运行在用户态的.

 

2.内核态和用户态的区别

那么,用户态和内核态又有什么区别呢?

📢我们先看内核态.在内核态上运行的所有程序,都是可以访问所有的硬件资源的,可以在硬件上执行各种指令

📢而用户态,只能执行一部分指令.对于那些影响系统稳定性的指令,还有I/O指令,都是不允许执行的.

 

但是有的人可能会提出疑问,我可以使用fopen()函数打开一个文件,并且还能对这个文件进行读写操作,我这个程序也是运行在用户态的,但是我可以做I/O操作呀.😦

其实我们不知道的是,C语言他默默帮我们封装了一个glibc库函数,并在里面调用了系统函数,然后由操作系统根据你传入的指令,比如打开文件指令,读取文件指令,去操作硬盘上的硬件,因此,glibc内部封装了一个接口程序,通过这个接口程序,去调用内核态的指令.🤗

3.特权指令和非特权指令 

在计算机中,存在指令集,指令集中有些指令是用户态上可以运行,有的只有在内核态上才能运行.

⌛我们将只有操作系统能使用,而用户不能使用的指令称为特权指令。

⌛而有一部分指令用户态和操作系统都能使用的就叫做非特权指令。

 因为不可能让应用程序或者程序员去擅自访问某个扇区中的二进制数据,必须要经过文件系统才能访问扇区中的数据.

🐞我们举个简单例子来说明:

这是一个最简单的HelloWorld程序

#include<stdio.h>
int main()
{

  char str[]="Hello World\n";
  printf("%s",str);
  return 0;
}

通过这个图我们可以看出来,在这个程序中,main函数肯定是运行在用户态的,在main函数中,还执行了一个printf函数,将HelloWorld打印输出到显示器中. 

它是将内存中的HelloWorld输出到控制台,目前这个printf函数是运行在用户态的,只不过打印输出的时候,printf肯定要和外部设备,比如说显示器打交道.

我们都知道操作系统内部有一个out指令,他就可以将内存中的数据输出到控制台,或者说输出到显示器中,所以这个时候,我们一定要做一个系统调用,让这个printf()跑到内核态中去执行.这个时候,也就是调用了操作系统的一个系统方法,或者说叫内部接口来和硬件交互.

我们首先使用gcc对这段代码进行编译,然后使用strace工具对代码进行跟踪.

 这个write()函数就是glibc封装的系统函数write(),也就是这个printf()函数在内部调用的系统函数write().

既然printf()调用的是write()函数,那么我们其实就可以直接将printf()函数替换为write()函数

#include<unistd.h>
int main()
{
  char msg[]="hello world\n";
  write(STDOUT_FILENO,msg,sizeof(msg)-1);
  return 0;
}

我们再次对程序进行编译,并且使用gdb跟踪调试. 

 

  1.  我们首先在write处打断点
  2. 然后run单步运行
  3. 最后进行反汇编 

确认了在write()函数的系统调用中,是通过syscall指令来将用户态陷入到了内核态.

接下来我们来看看用户态是如何切换到内核态的. 

1.将参数保存到寄存器中

这里也就是printf()的参数,或者说,在printf()内部调用的系统函数write()的参数

2.根据系统调用名称(也就是write()方法名)找到它的系统调用号.

这个系统调用号在哪里找呢?有一张系统调用映射表,这个映射表不仅在内核中维护了这样一张表,在glibc的库函数中,也维护了这样一张表,因此,我们就能够找到write()方法的系统调用号.

内核态和用户态之间通信就是通过系统调用号来进行的.

3.通过汇编指令syscall将用户态陷入到内核态,通过调用系统调用号对应的系统方法以及相关寄存器,来完成指令.

概括起来就是说,从用户态切换到内核态,就是用户态的应用程序要向内核态去申请外部资源,这个外部资源说通俗点也就是只有内核态才有权限执行的命令,就是外部资源.

说的更直白一点,就是当我们拆开一台服务器或者笔记本,肉眼可见的都属于外部资源,包括CPU,N=内存,网卡,硬盘,USB接口等等,都属于外部资源 

而系统调用,就是我们今天讲的syscall,就是最常见的陷入方式.

系统调用还有其它方式,分为5类

  • 进程  exit  fork
  • 文件  chomd  chown  open
  • 设备  read   write
  • 信息  getXXX  setXXX
  • 通信  mmap   sendfile

我们可以通过man syscalls命令来查看具体的系统调用

man syscalls

更多推荐

阿里云无影云电脑详细介绍:价格、使用和功能优势说明

什么是阿里云无影云电脑?无影云电脑(原云桌面)是一种快速构建、高效管理桌面办公环境,无影云电脑可用于远程办公、多分支机构、安全OA、短期使用、专业制图等使用场景,阿里云百科分享无影云桌面的详细介绍、租用价格、云电脑的优势、使用场景、网络架构、无影云电脑与云服务器的区别以及关于无影云电脑的常见问题解答FAQ:目录阿里云无

华为云云耀云服务器L实例评测|用PHP从数据库到后端到前端完整实现一个中秋节祝福语项目

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。🏆本文已收录于PHP专栏:PHP进阶实战教程,评测专区。🎉欢迎👍点赞✍评论⭐收藏文章目录🚀一、前言🚀二、

TCP详解之重传机制

TCP详解之重传机制TCP实现可靠传输的方式之一,是通过序列号与确认应答。在TCP中,当发送端的数据到达接收主机时,接收端主机会返回一个确认应答消息,表示已收到消息。但在错综复杂的网络,并不一定能如上图那么顺利能正常的数据传输,万一数据在传输过程中丢失了呢?所以TCP针对数据包丢失的情况,会用重传机制解决。接下来说说常

【C++】C++11(列表初始化和右值引用)

前言:C++的发展其实并不是一蹴而就的,他经历了很多阶段,本章开始,我们将进入C++11的学习。我们大致来看一下C++的发展历程:当然在这些之中还发行了其他的版本,C++还在不断的向后发展。但是:现在公司主流使用还是C++98和C++11。相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新

尚硅谷wepack课程学习笔记

为什么需要使用打包工具?开发时使用的框架、es6语法、less等浏览器无法识别。需要经过编译成浏览器能识别的css、js才可以运行。打包工具可以帮我们编译,号可以做代码压缩、兼容处理、性能优化。常见的打包工具有什么?vite、webpack、glup、gruntwebapck最基本的使用?是一个静态资源打包工具,以一个

@Valid注解的作用及@Valid注解与@Validated的区别

1.@Valid注解导入依赖<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId></dependency><dependency><groupId>org.hibernate.validator</g

面试官:你是怎么理解ES6中Proxy的?使用场景?

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录一、介绍二、用法参数handler解析Reflectget()set()deleteProperty()取消代理三、使用场景一、介绍定义:用于定义基本操作的自定义行为本质:修改的是程序默认形为,就形同于在编程语

ConfigMaps-1

文章目录主要内容一.使用YAML文件创建1.在data节点创建了一些键值:代码如下(示例):2.解释二.使用命令行创建1.创建了一个名为person的键值:代码如下(示例):2.解释3.创建了一个index.html文件,然后用--from-file来引用代码如下(示例):4.解释总结主要内容使用YAML文件创建使用命

Python 缓存库

文章目录缓存库缓存库的类型Python中有用的缓存库Python中的Redis缓存库Python中的lru_cache库Python中的其他缓存库总结缓存是一种可以存储数据以供快速访问的内存类型。它是一个小而快速的内存,用于保存经常访问的数据。缓存是至关重要的,因为它可以通过减少系统访问缓慢的主存储器的次数来提高系统性

【从入门到起飞】JavaAPI—System,Runtime,Object,Objects类

🎊专栏【JavaSE】🍔喜欢的诗句:更喜岷山千里雪三军过后尽开颜。🎆音乐分享【如愿】🎄欢迎并且感谢大家指出小吉的问题🥰文章目录🍔System类⭐exit()⭐currentTimeMillis()🎄用处⭐arraycopy()🍔Runtime类⭐创建对象⭐exit()⭐availableProcesso

写一篇nginx配置指南

nginx.conf配置找到Nginx的安装目录下的nginx.conf文件,该文件负责Nginx的基础功能配置。配置文件概述Nginx的主配置文件(conf/nginx.conf)按以下结构组织:配置块功能描述全局块与Nginx运行相关的全局设置events块与网络连接有关的设置http块代理、缓存、日志、虚拟主机等

热文推荐