系统调用的概念及原理

2023-05-16

系统调用与内核函数

内核函数与普通函数形式上没有什么区别,只不过前者在内核实现,因此要满足一些内核编程的要求。
系统调用是用户进程进入内核的接口层,它本身并非内核函数,但它是由内核函数实现的,进入内核后,不同的系统调用会找到相应的内核函数,这些内核函数被称为系统调用的“服务例程”。
比如系统调用getpid()实际调用的是服务例程sys_getpid(),也可以说,系统调用getpid()是服务例程sys_getpid()的“封装例程”。

系统调用基本概念

计算机的各种硬件资源是有限的,为了更好的管理这些资源,用户进程是不允许直接操作的,所有对这些资源的访问都必须由操作系统控制。为此操作系统为用户态运行的进程与硬件设备之间进行交互提供了一组接口,这组接口就是所谓的系统调用。

那么在应用程序和硬件之间设置这样一个接口层有什么优点呢?
1. 把用户从学习硬件设备的低级编程特性中解放出来。
2. 提高了系统的安全性,内核在满足某个请求之前就可以在接口级检查这个请求的正确性。
3. 最重要的是,这些接口使得程序更具有可移植性,因为只要不同操作系统所提供的一组接口相同,那么在这些操作
系统上就可以正确的编译和执行相同的程序。

系统调用实质上就是函数调用,只不过调用的是系统函数,处于内核态而已。 用户在调用系统调用时会向内核传递一个系统调用号,然后系统调用处理程序通过此号从系统调用表中找到相应的内核函数执行,最后返回。

系统调用号

Linux系统有几百个系统调用,为了唯一的标识每一个系统调用,Linux为每一个系统调用定义了一个唯一的编号,这个编号就是系统调用号。(在我的电脑上,它是在 /usr/include/x86_64-linux-gnu/asm/unistd_32.h, 可以通过 find / -name unistd_32.h -print 查找)。
在这里插入图片描述
系统调用号的另一个目的是作为系统调用表的下标,当用户空间的进程执行一个系统调用的时侯,这个系统调用号就被用来指明到底是要执行那个系统调用。

系统调用表

为了把系统调用号与相应的服务例程关联起来,内核利用了一个系统调用表,存放在sys_call_table数组中,它是一个函数指针数组,每一个函数指针都指向其系统调用的封装例程,有NR_syscalls个表项,第n个表项包含系统调用号为n的服务例程的地址。

系统调用处理函数

系统调用最终还是会由内核函数完成,那么为什么不直接调用内核函数呢?
这是因为用户空间的程序无法直接执行内核代码,因为内核驻留在受保护的地址空间上,不允许用户进程在内核地址空间上读写。所以,应用程序会以某种方式通知系统,告诉内核需要执行一个函数调用,这种通知机制是靠软中断来实现的,通过引发一个异常来促使系统切换到内核态去执行异常处理程序。此时的异常处理程序就是所谓的系统调用处理程序。

系统调用是属于操作系统内核的一部分,必须以某种方式提供给进程让它们去调用。CPU可以在不同的特权级别下运行,
而相应的操作系统也有不同的运行级别,用户态和内核态。运行在内核态的进程可以毫无限制的访问各种资源,
而在用户态下的用户进程的各种操作都有着限制,比如不能随意的访问内存、不能开闭中断以及切换运行的特权级别。
所以操作系统通过中断从用户态切换到内核态。

补充——中断是什么

中断控制是计算机发展中一种重要的技术。 最初它是为克服对I/O接口控制采用程序查询所带来的处理器效率低而产生的。
中断控制的主要优点是只有在I/O需要服务时才能得到处理器的响应,而不需要处理器不断地进行查询。
由此,最初的中断全部是对外部设备而言的,称为外部中断(或硬件中断)。
但随着计算机系统结构的不断改进以及应用技术的日益提高,中断的适用范围也随之扩大,出现了所谓的内部中断(或叫异常),
它是为解决机器运行时所出现的某些随机事件及编程方便而出现的。因而形成了一个完整的中断系统。

中断可分为两大类:异常中断
异常分为故障陷阱特点是既不使用中断控制器,也不能被屏蔽(异常实际上是CPU发出的中断信号)。
中断分为外部可屏蔽中断和外部非屏蔽中断,所有I/O设备产生的中断请求均引起屏蔽中断,而紧急事件(如硬件故障)引起的故障产生非屏蔽中断。

Intel x86系列微机共支持256中向量中断,Linux对256个向量的分配如下:
(1) 从0~31的向量对应异常和非屏蔽中断。
(2) 从32~47的向量分配给屏蔽中断。
(3) 从48~255的向量用来标识软中断。Linux只用了其中一个(128向量即0x80向量)用来实现系统调用。
注:Linux为什么只使用一个中断号来对应所有的系统调用,而不是一个中断号对应一个系统调用?
因为中断号是有限的,而系统调用又太多了。

Linux对系统调用的调用必须通过执行int $0x80汇编指令,这条指令会产生向量为128的编程异常。

中断有两个重要的属性,中断号中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表,这个数组存储了所有中断处理程序的地址,而中断号就是相应中断在中断向量表中的偏移量。

在实地址模式中,CPU把内存中从0开始的1KB用来存储中断向量表。表中的每个表项占4个字节,
由两个字节的段地址和两个字节的偏移量组成,这样构成的地址便是相应的中断处理程序的入口地址。
但是,在保护模式下,由4字节的表项构成的中断向量表显然满足不了要求。这是因为:
<1>除了两个字节的段描述符,偏移量必须用4字节来表示;
<2>要有反映模式切换的信息。
因此,在保护模式下,中断向量表中的表项由8个字节组成,中断向量表也改叫做中断描述符表
IDT(Interrupt Descriptor Table)。其中的每个表项叫做一个门描述符(Gate Descriptor),
“门”的含义是当中断发生时必须先通过这些门,然后才能进人相应的处理程序。

Linux下系统调用原理

根据上文,我们知道Linux使用一个中断号来对应所有的系统调用,那么只有一个中断号,操作系统怎么知道是哪一个系统调用要被调用呢?
上文也提到过,系统调用拥有自己的系统调用号,系统调用表以及系统调用处理函数。一个调用号对应一个处理函数,通过处理函数和调用号在调用表中找到相应的系统调用。

在Linux中,EAX寄存器是负责传递系统调用号的。
以fork()为例,fork()的系统调用号为2,在执行int $0x80指令前,调用号会被存放在eax寄存器中,系统调用处理函数(中断处理函数)最终会通过系统调用号,调用正确的系统调用。

伪代码:
movl eax,2
int 0x80

在这里插入图片描述系统调用除了需要传递系统调用号以外,还是需要传递参数,并且具有返回值的,那么参数是怎么传递的呢?
对于参数传递,Linux也是通过寄存器完成的。Linux最多允许向系统调用传递6个参数,
分别依次由%ebx,%ecx,%edx,%esi,%edi和%ebp这个6个寄存器完成。

以调用exit(1)为例

伪代码:
movl eax,2
movl ebx,1
int 0x80

因为exit需要一个参数1,所以这里只需要使用ebx。这6个寄存器可能已经被使用,所以在传参前必须把当前寄存器的状态保存下来,待系统调用返回后再恢复。

Linux中,在用户态和内核态运行的进程使用的栈是不同的,分别叫做用户栈和内核栈, 两者各自负责相应特权级别状态下的函数调用。当进行系统调用时,进程不仅要从用户态切换到内核态,同时也要完成栈切换, 这样处于内核态的系统调用才能在内核栈上完成调用。系统调用返回时,还要切换回用户栈,继续完成用户态下的函数调用。

寄存器%esp(栈指针,指向栈顶)所在的内存空间叫做当前栈, 比如%esp在用户空间则当前栈就是用户栈,否则是内核栈。栈切换主要就是%esp在用户空间和内核空间间的来回赋值。 在Linux中,每个进程都有一个私有的内核栈,当从用户栈切换到内核栈时,需完成保存%esp以及相关寄存器的值(%ebx,%ecx…)并将%esp设置成内核栈的相应值。而从内核栈切换会用户栈时,需要恢复用户栈的%esp及相关寄存器的值以及保存内核栈的信息。

之前总是听说系统调用很费时,在学习了系统调用的原理后,我们应该也知道了其中的原因

  1. 系统调用通过中断实现,需要从用户态切换到内核态,也就是要完成栈切换。
  2. 会使用寄存器传参,需要额外的保存和恢复的过程。

以上关于系统调用的总结,都是本人从书本以及网上的资料,博客学习到的,如果由什么不对的地方,欢迎指正。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

系统调用的概念及原理 的相关文章

  • ubuntu运行maude提示error while loading shared libraries: libtinfo.so.5

    ubuntu运行maude提示 maude linux64 error while loading shared libraries libtinfo so 5 cannot open shared object file No such
  • connect to host port 22: Connection refused

    Windows 使用SSH连接树莓派 xff1a 提示 xff1a 这里简述项目相关背景 xff1a 今天练习发现使用MobaXterm可以正常连接到树莓派 xff0c 但是使用windows终端就不可以连接 xff0c 显示connect
  • windows通过SSH控制树莓派

    windows通过SSH控制树莓派 xff1a 因学习需要在windows系统下对树莓派进行SSH连接 xff0c 包括SSH密钥生成 密钥传输及公钥保存等 Windows下密钥的产生 在Windows下使用 ssh keygen生成公钥和
  • raspistill command not found

    raspistill command not found xff1a 提示 xff1a 这里简述项目相关背景 xff1a 今天使用树莓派来调用摄像头 xff0c 摄像头为树莓派官方摄像头 xff0c 在升级系统和配置后发现使用raspist
  • 树莓派I2C基本用法

    文章目录 一 I2C二 I2C配置1 I2C02 I2C13 I2C34 I2C45 I2C56 I2C6 三 I2C工具总结 一 I2C 树莓派默认打开I2C功能 xff0c 如果I2C没有打开 xff0c 可以使用命令sudo rasp
  • 树莓派RTC

    文章目录 一 RTC准备二 RTC芯片三 为什么使用hwclock显示找不到硬件总结 一 RTC准备 在使能树莓派RTC之前 xff0c 需要先为树莓派RTC模块安装电池 xff08 一般为纽扣电池 xff09 二 RTC芯片 树莓派4B使
  • cpptools占用率过高

    问题描述 使用vscode发现在系统中cpptools CPU占用率达到百分百 电脑发生严重卡顿 解决方案 xff1a 此问题的出现是因为使用了C C 43 43 这个插件 xff0c 如果直接禁用此插件就可以解决这个问题 如果希望使用这个
  • c语言状态机系统

    读取文件并实现了把里面的数字读取出来并加以求平均数 include lt stdio h gt include lt string h gt using namespace std int a1 1000009 int r 61 0 int
  • 快速创建kvm虚拟机(shell)

    通过脚本的方式 xff0c 快速复制kvm虚拟机 更改脚本变量 使用脚本 结果展示 脚本如下 xff0c 已测试通过 usr bin env bash coding utf 8
  • windows安装虚拟机 Linux-ubuntu20.04.6 LTS x86_64(Py3.7.9)详细教程

    安装虚拟机 首先需要下载vmware 注意版本 xff0c 这里我下载的版本是 vmware最新版 xff08 17 0 0 build 20800274 xff09 17 0 0 build 20800274版本的密钥 xff1a MC6
  • 基于51单片机实现时间显示及闹钟设置

    文章目录 一 介绍二 原理三 步骤四 结果五 结果分析六 总结 一 介绍 本次为大学中的一次创新实验 xff0c 当时老师叫我自己拿个单片机去玩 xff0c 为了赶时间就做了个简单的时间显示和闹钟设置 xff0c 因为比较简单所以也把代码附
  • vim 文本替换

    常规替换 n1 span class token punctuation span n2s hello world g span class token operator span 用world替换文件n1行到n2行所有的hello n1
  • 51单片机定时器工作方式1、2原理详解

    写在前面 1 本篇博文旨在帮助那些像我一样刚入门51单片机 xff0c 如果你对定时器有一定了解 xff0c 但是其中的的工作方式不能理解 xff0c 那么这篇文章很适合你 xff0c 如果你是大神的话 直接绕行吧 2 我在学习的过程中由于
  • 虚拟机Ubuntu连接不了网络的解决方法

    昨晚上虚拟机ubuntu中网络还是正常使用的今天准备安装一个nfs服务发现无法使用apt工具了 xff0c 然后才发现虚拟机没网了 xff0c 然后在百度试了两种方法没有效果 方法1 xff1a 尝试输入以下命令来解决 xff1a span
  • 安装Anaconda并配置环境变量

    安装Anaconda并配置环境变量 下载安装配置变量 下载安装 anaconda官网 xff1a https www anaconda com 选择需要的版本进行下载 https www anaconda com products dist
  • OrCAD 导出 BOM 表

    BOM 表简介 BOM表是什么呢 xff1f 它的全称 xff08 Bill Of Material xff09 即物料清单的意思 顾名思义 xff0c 一个产品的BOM说明了这个产品总共需要多少零配件来组装 所有的PCBA制造商都需要根据
  • Allergo 导出光绘(Gerber)文件及坐标文件

    文章目录 导出 Gerber光绘介绍设置输出文件夹和路径生成钻孔信息导出光绘 ArcworkGerber 生成报错 database has error 导出坐标文件坐标文件介绍生成坐标文件 参考资料 导出 Gerber 光绘介绍 Gerb
  • cpp-http 库的使用

    文章目录 前言 96 cpp http 96 库简介 96 cpp http 96 库使用介绍http 客户端搭建步骤http 服务端搭建步骤 96 cpp http 96 库示例服务端实现客户端实现 示例下载关于示例代码编译出错的问题 参
  • esp32 开发环境搭建

    文章目录 前言提示构建工具安装 IDF设置 idf 目标平台 设定环境变量同时安装多个版本安装 idf 和 tools修改环境变量 参考资料ESP IDF 快速入门编译 ESP AT 工程idf py build 出现cmake faile
  • Latex之给字符上加横线、波浪线、^等

    加 号 xff1a hat x 加波浪线 xff1a widetilde x 加两个点 xff1a ddot x 以上几种对应结果 xff1a 如果是在正文中 xff1a 要在左右带上 公式添加 xff1a overline X 61 fr

随机推荐

  • linux操作系统远程登录拷贝

    1 SSH远程登录 xff1a 命令格式 xff1a ssh 用户名 64 IP地址 命令选项ssh远程登录scp远程拷贝 说明 SSH是专门为远程登录提供的一个协议 xff0c 常用于远程登录 xff0c 使用前需要安装相应的服务和客户端
  • VMware的Debian11如何删除磁盘文件,并在扩充原有磁盘

    删除原有磁盘分区 1 在 虚拟机 gt 设置 中 xff0c 选中需要删除的磁盘分区文件 xff0c 点击 移除 xff1b 2 如果此磁盘已设置开机自动挂载 xff0c 需要取消挂载 xff1a xff08 1 xff09 在 root
  • 计算机视觉思维导图

    计算机视觉思维导图 最近整理的计算机视觉思维导图分享给大家 xff0c 来源于各个教学视频以及博客 xff0c 可以当做字典使用 xff0c 知道整个行业的方向及相关技术 xff0c 按照自己理解的视觉处理任务顺序排序
  • centos8安装docker错误解决

    安装出现 Problem problem with installed package buildah Last metadata expiration check 0 08 17 ago on Sat 20 Feb 2021 12 43
  • c中输入一个十进制数,输出它的八进制二进制以及十六进制

    代码 xff1a span class token macro property span class token directive keyword include span span class token string lt stdi
  • 如何删除Alibaba PC Safe Service

    如何删除Alibaba PC Safe Service Alibaba PC Safe Service是AlibabaProtect服务项目 xff0c Alibaba PC Safe Service这个东西在任务管理器里你是如论如何都关不
  • Yapi-从零搭建接口管理平台

    介绍 旨在为开发 产品 测试人员提供更优雅的接口管理服务 可以帮助开发者轻松创建 发布 维护 API xff1b 官网网址 xff1a YApi 教程 hellosean1025 github io 搭建 其实官网有明确的搭建方法 xff0
  • Sql 数据库细节全解(icelei讲sql)

    磊哥哥讲Sql 一 what who defined1 数据库whatever2 引言导入 二 database and tables guy1 Basic element project definition2 template data
  • 编写一个Shell函数检查Linux系统中某文件的权限是否小于一个值

    我编写了一个Shell函数 xff0c 使用这个函数需要传两个参数 xff1a 文件绝对路径和一个三位整数 通过这个函数可以检查文件权限是否小于等于你给定的值 submod export filepath 61 1 export maxmo
  • codeforces 1328 B. K-th Beautiful String

    题意 xff1a 就是找到第 k k k 个全排列的字符串 通过找规律 xff0c 第一个 b b b 在倒数第二位有
  • 使用python 解ccf-csp 2019-03-1小中大

    传送 问题描述 问题分析 这个题目最大值和最小值很好得到 xff0c 因为已经排好序了 xff0c 只需要判断一下是正序还是反序就可以了 xff0c 至于中位数我们得先清除它的概念 xff0c 如果不清楚 xff0c 也可以从给出来的例子判
  • ubuntu生成anaconda快捷方式

    https blog csdn net weixin 45653050 article details 105636020
  • 编码转换

    编码定义 在计算机硬件中 xff0c 编码 xff08 coding xff09 是在一个主题或单元上为数据存储 xff0c 管理和分析的目的而转换信息为编码值 xff08 典型地如数字 xff09 的过程 在软件中 xff0c 编码意味着
  • Visual Studio Code安装go插件报错

    VScode第一次跑go代码时提示The go outline command is not available Run 34 go get v github com ramya r有效解决安装方法 出现问题 xff1a Visual St
  • TCP实现服务器与客户端的连接(多线程)

    上一篇博客中 xff0c 我们用TCP实现了服务器与客户端的连接 但是有一个问题 xff0c 即一个客户端在和服务器交互时 xff0c 其他客户端无法连接 xff0c 为解决这一问题 xff0c 我们将服务器端改造为线程池的版本 xff08
  • 【GIT】在kali linux上安装git与码云提交|kali安装wps

    xff11 安装git kali自带 xff0c xff08 apt get install git xff09 2 添加git服务用户 xff08 这一步不知道有没有用也输入了 xff0c 只是有点问题 xff09 useradd git
  • Windows10系统重装之U盘安装

    1 准备工作 操作系统 xff1a Windows 10 安装工具 xff1a U盘安装 程序下载 xff1a MediaCreationTool 链接 xff1a https pan baidu com s 1GTnFze86sDjRnV
  • ubuntu18.04安装cuda和cudnn

    一 安装 cuda 1 首先查看自身电脑最高支持的cuda版本为多少 xff0c 在终端输入以下指令 nvidia smi 可以看到我的最高支持 cuda 11 4 2 打开英伟达官网 下载官方cuda 此处我下载的是cuda 11 0 3
  • 批处理打开指定路径下的所有文件

    需求 xff1a 批处理打开指定路径下的所有文件 前提 xff1a 默认各位同学已经熟悉常用的各种批处理命令 xff0c 本文仅对涉及到的批处理命令做简单的介绍 xff0c 有需要进一步学习 xff0c 可查阅网上其它资料 也可通过CMD命
  • 系统调用的概念及原理

    系统调用与内核函数 内核函数与普通函数形式上没有什么区别 xff0c 只不过前者在内核实现 xff0c 因此要满足一些内核编程的要求 系统调用是用户进程进入内核的接口层 xff0c 它本身并非内核函数 xff0c 但它是由内核函数实现的 x