系统调用与函数调用有什么区别?

本文我们来聊聊系统调用与普通的函数调用之间的区别。

作为程序员你肯定写过无数的函数,假设有这样两个函数:

void funcB() {}
void funcA() {  funcB();}

函数之间是可以相互调用的,这很简单很happy有没有。

要知道是代码、是函数就可以相互调用,不管你用什么语言写的。

假设funcB是内核中的函数,funcA是你自己写的函数,就像这样:

 

// Linux内核中的函数void funcB() {}
// 你的函数void funcA() { funcB();}

那么funcA应该也能调用funcB(如果funcB可以供外界调用的话)。

有的同学可能会惊呼,我们可以自己编写代码调用操作系统的函数,那岂不是可以直接控制操作系统了?

too yong too simple!

如果我们编写的代码可以直接调用所有的操作系统函数那么从某种程度上讲的确可以说是能控制操作系统,但如果操作系统只允许你调用内核中的有限的几个函数呢?

怎么样,你(应用程序)是不是就被限制住了。

你又会问,操作系统是怎样限制应用程序能调用哪些内核中的函数呢?

实际上单靠操作系统这种软件是没有办法限制应用程序能调用哪些以及多少个内核函数的,因此为施加这种限制必须依靠——硬件。

这里的硬件指的就是CPU。

那么CPU又是怎么施加这种限制的呢?

我们先来看看普通的函数调用,函数调用对应的机器指令是call指令,就像这样:

 

call 0x400410

call指令后的这个地址0x400410就是被调函数的第一条机器指令所在的内存地址。

当CPU执行到这条机器指令时直接跳转到对应的地址继续执行指令,从程序员的角度看就是函数调用。

而如果是我们程序的函数调用操作系统的函数就不允许使用call指令了,而是syscall机器指令(x86_64)。

使用syscall指令调用操作系统函数时也是把相应函数的第一条指令的地址放到syscall之后吗?

显然不是的,因为操作系统系统代码和你的代码都是单独编译以及运行的,你根本就不知道操作系统的某个函数存放在内存的什么位置上,也不应该让你知道,因此使用syscall调用操作系统的函数时我们只能附加一个序号,比如序号0对应操作系统中的A函数、序号1对应操作系统中的B函数等等,这样使用syscall指令时只需要将该序号写入rax寄存器即可,CPU在执行syscall指令时通过读取rax寄存器的值就能知道到底该调用操作系统中的哪个函数了。

可以看到,利用这种机制操作系统限制了应用程序可以调用哪些内核中的函数。

有的同学可能会有疑问,如果一个call指令因为种种原因后面跟上的地址”无意“中指向了一个内核函数的地址,那么CPU执行call指令时会怎样呢?就像这样:

call 0x400410

这里假设0x400410这个地址指向了一个内核函数地址。

很简单,CPU在执行这条指令时会判断出当前进程没有权限访问0x400410这个地址,因此CPU在执行这条指令时会产生异常,该进程会被直接kill掉。

这里列举了Linux在各种处理器上怎样进行系统调用。

图片

看到了吧,syscall和call在使用方法上还是有很大不同的,可以看到call是直接调用的,也就是说应用程序这一层中的函数调用是直接调用的,而syscall其实是间接调用的,即我们调用操作系统中的函数时其实是间接调用的。

除此之外,CPU在执行call指令以及syscall指令时另外一个不同点在于模式的切换。

当CPU执行普通函数时其实是运行在用户态,user mode,在这种模式下CPU不能执行某些特权指令,这也就意味着我们的程序其实是受限的;而当CPU执行syscall开始执行操作系统的代码时会切换到内核态,kernel mode,在这种模式下CPU可以执行任何特权指令,不受任何限制,操作系统才是真正的管理计算机的大boss。

可以看到,当在普通程序中进行函数调用时就是函数调用,而普通函数调用操作系统中的函数时才叫系统调用。

最后再说一点,普通的函数调用所使用的栈全部位于进程的栈区,假设main函数调用funcA函数,funcA调用funcB函数,那么此时的进程内存布局就像这样:

图片

而进行系统调用时当CPU开始执行操作系统的代码时不再基于进程栈区而是会跳转到操作系统某个特定内存区域,该区域作为进程在内核中的栈区,因此也叫做内核栈,每个进程在内核中都有自己的内核栈,因此我们可以看到一个进程其实有两个栈区,一个在用户态一个在内核态。

假设main函数调用funcA,funcA进行系统调用,调用内核中的funcB函数,funcB函数调用内核中的funcC函数,那么此时的内存布局就像这样:

图片

好啦,这个话题就到这里,希望对大家理解操作系统有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/22216.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试要学习哪些技术才能月入15K

目录 前言 一、Linux必备知识 二、Shell脚本 三、互联网程序原理 四、Mysql数据库 五、抓包工具 六、接口测试工具 七、Web自动化测试Java&Pyhton 八、接口与手机自动化 九、敏捷测试&TestOps构建 十、性能测试&安全测试 总结: 前言 我一直…

[chatgpt+Azure]unity AI二次元小女友之使用微软Azure服务实现RestfulApi->语音识别+语音合成

1.简述 如题所述,这个小项目是在unity引擎端,使用了chatgpt微软azure的一个AI二次元女友对话的项目,实现原理也比较简单,即在unity端实现AI二次元女友的交互界面,接入chatgpt-3.5-turbo的api接口,借助chatg…

LabVIEW和Web Service交互方式?LabVIE本地项目如何发布到互联网上让外网访问

LabVIEW全称Laboratory Virtual Instrument Engineering Workbench, 是一种图形化编程语言(通常称为G语言),即实验室虚拟仪器集成环境。LabVIEW 经过多年的持续创新,已经从单纯的仪器控制软件发展成为面向设计、测量和控制的综合性图形化开发…

【详解】C语言冷门知识点之--位段

文章目录 一, 位段的解释二, 位段的声明和使用位段的声明:位段的使用: 三,位段的空间大小计算第一个例子:第二个例子:注意: 四, 位段的内存分配五,位段的跨平…

Visual Studio下2022Opencv的配置

Visual studio2022 opencv的配置 先从官网下载opencv : opencv releases 下载 ​ 我这里的开发环境是window版本,我们选择Windows版本进行下载 点开下载的文件,输入需要保存的路径 记住你保存的路径(我这里安装再F:) 安装需要时间静等安装…

基于单片机的盲人导航智能拐杖老人防丢防摔倒发短息定位

功能介绍 以STM32单片机作为主控系统; OLED液晶当前实时距离,安全距离,当前经纬度信息;超声波检测小于设置的安全距离,蜂鸣器报警提示:低于安全距离!超声波检测当前障碍物距离,GPS进…

综合小实验

第一步:计划IP R1的环回:192.168.1.0/28 R2的环回:192.168.1.16/28 R123的O/O/0接口:192.168.1.32/28 R3-4:192.168.1.128/30 Vlan2:192.168.1.48/28 vlan3:192.168.1.64/28 192.168.1.0/24 0区…

深度学习——优化器Optimizer

代码以及详细注释: import torch import torch.utils.data as Data import torch.nn.functional as F import matplotlib.pyplot as plt# torch.manual_seed(1) # reproducible """超参数 """ # 学习率 LR 0.01 # 批大小 BATCH_…

Java中abstract关键字

文章目录 由来语法格式使用说明应用举例 由来 举例1: 随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它…

【模式识别目标检测】——基于机器视觉的无人机避障RP-YOLOv3实例

目录 引入 一、YOLOv3模型 1、实时目标检测YOLOv3简介 2、改进的实时目标检测模型 二、数据集建立&结果分析 1、数据集建立 2、模型结果分析 三、无人机避障实现 参考文献: 引入 目前对于障碍物的检测整体分为:激光、红外线、超声波、雷达、…

【超全面】Linux嵌入式干货学习系列教程

文章目录 一、前言二、Linux基础篇三、数据结构与算法基础三、Linux应用篇四、Linux网络篇五、ARM篇六、Linux系统移植篇七、Linux驱动篇八、Linux特别篇九、Linux项目篇 一、前言 博主学习Linux也有几个月了,在这里为广大朋友整理出嵌入式linux的学习知识&#xff…

Matplotlib入门与实践(一)

Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形。通过 Matplotlib,开发者可以仅需要几行代码,便可以生成绘图,直方图,功率谱,条形图,错误…