服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

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

日期: 来源:码农的荒岛求生收集编辑:码农的荒岛求生
大家新年好,我是小风哥,这是今年的第一篇技术文,我们来聊聊系统调用与普通的函数调用之间的区别。

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

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函数,那么此时的内存布局就像这样:

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

最后,我建了微信技术群,扫描下方二维码备注写“加群”二字即可,一起见证我们的成长。







相关阅读

  • 深入理解Linux系统调用

  • 大家好,我是小风哥。在前两篇文章《为什么计算机需要操作系统》《系统调用与函数调用有什么区别》中我们了解了什么是系统调用、为什么需要系统调用、系统调用与函数调用有什
  • 产品更新 | 网镜国产化操作系统版本正式上线

  • 关于本次网镜更新推文,小编想说我们为什么要做支持国产化操作系统的应用。为什么要毫不动摇坚持自主可控的“国产化”道路?不自主意味着需要在国际市场上高价采购;不可控意味着
  • NDK开发之 JNI 静态注册与动态注册

  • 一、起因前段时间学习OpenGL ES相关技术,下载了一个Github项目学习,项目地址在:https://github.com/githubhaohao/NDK_OpenGLES_3_0项目的关键代码都是C++实现的,所以需要使用JN
  • Kotlin 高阶函数与 Standard.kt 源码详解

  • 前言在Kotlin中,高阶函数是指将一个函数作为另一个函数的参数或者返回值。如果用f(x)、g(x)用来表示两个函数,那么高阶函数可以表示为f(g(x))。Kotlin为开发者提供了丰富的高
  • Kotlin 协程能完全取代 RxJava 吗?

  • 作者:RainyJiang https://juejin.cn/post/7175803413232844855背景自从 jetbrains 公司提出 Kotlin 协程用来解决异步线程问题,并且衍生出来了 Flow 作为响应式框架,引来了大量
  • 厉害了,Kotlin 协程能完全取代 RxJava?

  • 安卓进阶涨薪训练营,让一部分人先进大厂大家好,我是皇叔,最近开了一个安卓进阶涨薪训练营,可以帮助大家突破技术&职场瓶颈,从而度过难关,进入心仪的公司。详情见文章:没错!皇叔开了

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

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

  • 大家新年好,我是小风哥,这是今年的第一篇技术文,我们来聊聊系统调用与普通的函数调用之间的区别。作为程序员你肯定写过无数的函数,假设有这样两个函数:void funcB() {}void func
  • 深入理解Linux系统调用

  • 大家好,我是小风哥。在前两篇文章《为什么计算机需要操作系统》《系统调用与函数调用有什么区别》中我们了解了什么是系统调用、为什么需要系统调用、系统调用与函数调用有什
  • 世界糖尿病日||中医话中医糖尿病“消渴病”

  • 2022.11.14世 界 糖 尿 病 日控制血糖全身健康- 人人享有糖尿病健康管理 -中医话·糖尿病西医学中的糖尿病在中医归属于“消渴病”的范畴,消渴是以多饮、多食、多尿、身体消
  • 喜讯!25项科研成果获奖,获奖数创历史新高!

  • 本文转自北京中医药大学官方公众号近日,中华中医药学会公布了2022年度中华中医药学会科学技术奖励评审结果。我校前期积极进行相关宣讲、做好组织申报工作,并召开多轮专家论证
  • ChatGPT与超级个体的诞生

  • 大家好,我是小风哥,这是一份迟来的chatGPT评测。今天简单试了下,试完有想充会员的冲动,Google这么慌是有道理的,这东西的确有点颠覆的意思,使用过程中后背阵阵发凉,这个工具会让能
  • 拖了个拖,快给自己一颗抗拖延妙药吧

  • 本文转自北京中医药大学官方公众号\ | /想想今晨的你是不是窝在宿舍暖洋洋的床上在计划应该学习的时间里打开手机摸着鱼是不是为了双十一熬了夜红了眼守着整点去抢个限时秒