系统调用概述

计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同一时候执行的多个进程都须要訪问这些资源,为了更好的管理这些资源进程是不同意直接操作的,全部对这些资源的訪问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call)。在linux中系统调用是用户空间訪问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口。

普通情况下应用程序通过应用编程接口API,而不是直接通过系统调用来编程。

在Unix世界,最流行的API是基于POSIX标准的。

操作系统通常是通过中断从用户态切换到内核态。中断就是一个硬件或软件请求,要求CPU暂停当前的工作,去处理更重要的事情。

比方。在x86机器上能够通过int指令进行软件中断。而在磁盘完毕读写操作后会向CPU发起硬件中断。

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

一般地,系统调用都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产生,而128号异常处理程序就是系统调用处理程序system_call()。它与硬件体系有关。在entry.S中用汇编写。

接下来就来看一下Linux下系统调用详细的实现过程。

Linux下系统调用的实现

前文已经提到了Linux下的系统调用是通过0x80实现的,可是我们知道操作系统会有多个系统调用(Linux下有319个系统调用),而对于同一个中断号是怎样处理多个不同的系统调用的?最简单的方式是对于不同的系统调用採用不同的中断号。可是中断号明显是一种稀缺资源,Linux显然不会这么做;另一个问题就是系统调用是须要提供參数,而且具有返回值的,这些參数又是怎么传递的?也就是说。对于系统调用我们要搞清楚两点:

1. 系统调用的函数名称转换。

2. 系统调用的參数传递。

首先看第一个问题。实际上,Linux中每一个系统调用都有对应的系统调用号作为唯一的标识,内核维护一张系统调用表,sys_call_table,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量。在x86上,系统调用号是通过eax寄存器传递给内核的。比方fork()的实现:

在/usr/include/asm/unistd_32.h,能够通过find / -name unistd_32.h -print查找)

  1. #ifndef _ASM_X86_UNISTD_32_H
  2. #define _ASM_X86_UNISTD_32_H
  3. /*
  4. * This file contains the system call numbers.
  5. */
  6. #define __NR_restart_syscall      0
  7. #define __NR_exit                 1
  8. #define __NR_fork                 2
  9. #define __NR_read                 3
  10. #define __NR_write                4
  11. #define __NR_open                 5

所以详细调用fork的过程是:将2存入%eax中,然后进行系统调用,伪代码:

  1. mov     eax, 2
  2. int     0x80

对于參数传递,Linux是通过寄存器完毕的。Linux最多同意向系统调用传递6个參数,分别依次由%ebx,%ecx,%edx,%esi,%edi这5个寄存器完毕,须要6个及以上參数情况不多见。另外应该有一个单独的寄存器存放指向全部这些參数在用户空间的地址的指针。给用户空间的返回值通过eax寄存器传递。比方,调用exit(1),伪代码是:

  1. mov    eax, 2
  2. mov    ebx, 1
  3. int    0x80

由于exit须要一个參数1,所以这里仅仅须要使用ebx。这6个寄存器可能已经被使用,所以在传參前必须把当前寄存器的状态保存下来,待系统调用返回后再恢复,这个在后面栈切换再详细讲。

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

寄存器%esp(栈指针。指向栈顶)所在的内存空间叫做当前栈,比方%esp在用户空间则当前栈就是用户栈。否则是内核栈。栈切换主要就是%esp在用户空间和内核空间间的来回赋值。

在Linux中,每一个进程都有一个私有的内核栈,当从用户栈切换到内核栈时,需完毕保存%esp以及相关寄存器的值(%ebx。%ecx...)并将%esp设置成内核栈的对应值。

而从内核栈切换会用户栈时。须要恢复用户栈的%esp及相关寄存器的值以及保存内核栈的信息。一个问题就是用户栈的%esp和寄存器的值保存到什么地方,以便于恢复呢?答案就是内核栈,在调用int指令机型系统调用后会把用户栈的%esp的值及相关寄存器压入内核栈中。系统调用通过iret指令返回。在返回之前会从内核栈弹出用户栈的%esp和寄存器的状态。然后进行恢复。

相信大家一定听过说,系统调用非常耗时。要尽量少用。通过上面描写叙述系统调用的实现原理,大家也应该知道这当中的原因了。

第一,系统调用通过中断实现,须要完毕栈切换。

第二,使用寄存器传參,这须要额外的保存和恢复的过程。

上面关于系统调用的阐述,如有错误欢迎指正。。

Linux系统调用具体解释(怎样从用户空间进入内核空间)的更多相关文章

  1. Linux用户空间与内核空间(理解高端内存)

    Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...

  2. Linux用户空间与内核空间

    源:http://blog.csdn.net/f22jay/article/details/7925531 Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针 ...

  3. linux 用户空间与内核空间——高端内存详解

    摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对 ...

  4. linux用户空间和内核空间(内核高端内存)_转

    转自:Linux用户空间与内核空间(理解高端内存) 参考: 1. 进程内核栈.用户栈 2. 解惑-Linux内核空间 3. linux kernel学习笔记-5 内存管理   Linux 操作系统和驱 ...

  5. Linux用户空间与内核空间(理解高端内存)【转】

    转自:http://www.cnblogs.com/wuchanming/p/4360277.html Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递 ...

  6. 在Linux用户空间做内核空间做的事情

    导读 我相信,Linux 最好也是最坏的事情,就是内核空间(kernel space)和用户空间(user space)之间的巨大差别.如果没有这个区别,Linux 可能也不会成为世界上影响力最大的操 ...

  7. Linux内存管理--用户空间和内核空间【转】

    本文转载自:http://blog.csdn.net/yusiguyuan/article/details/12045255 关于虚拟内存有三点需要注意: 4G的进程地址空间被人为的分为两个部分--用 ...

  8. linux内存管理--用户空间和内核空间

    关于虚拟内存有三点需要注意: 4G的进程地址空间被人为的分为两个部分--用户空间与内核空间.用户空间从0到3G(0xc0000000),内核空间占据3G到4G.用户进程通常情况下只能访问用户空间的虚拟 ...

  9. 如何看待Linux操作系统的用户空间和内核空间

    作为中央核心处理单元的CPU,除了生产工艺的不断革新进步外,在处理数据和响应速度方面也需要有权衡.稍有微机原理基础的人都知道Intel X86体系的CPU提供了四种特权模式ring0~ring3,其中 ...

随机推荐

  1. sublime text 快键键

    sublime text 的快捷键ctrl+l                              选择整行(按住-继续选择下行)ctrl+shift+k                    ...

  2. xml之基本操作

    XML:Extensible Markup Language(可扩展标记语言)的缩写,是用来定义其它语言的一种元语言,其前身是SGML(Standard Generalized Markup Lang ...

  3. SQLServer2008 关于CASE WHEN

    CASE WHEN的两种格式 1.简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END 2.Case搜索函数 CASE ...

  4. ViewPager PagerAdapter 的使用

    1: 目的,实现全屏滑动的效果 2:类似于BaseAdapter public class MyPagerAdapter extends PagerAdapter { private Context ...

  5. mui图片懒加载

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

  6. AI:狄拉克之海上的涟漪

    延陵季子2011年  8月27日 19:02   借鉴英文原文:Ripples in the Dirac Sea 当他试着用一种轻松的口吻诉说一些事情时,我会明白,其实我们都明白,在他的心里绝对不是平 ...

  7. 《计算机图形学基础(OpenGL版)》勘误表

    第1版第1次印刷: 所在页码 所在行 原内容 更正为 41 16 k=Δx/Δy k=Δy/Δx 46 6 s-t=2Δy/Δx(xi+1)+2b+2yi-1 s-t=2Δy/Δx(xi+1)+2b- ...

  8. html中的小知识

    引用外部样式 样式表,如果是引用外部样式,不需要再写style标签了,因为 <link rel="stylesheet" type="text/css" ...

  9. apicloud图片上传

    app中的图片上传,例如:个人信息页面,上传头像 使用: UIMediaScanner 地址: https://docs.apicloud.com/Client-API/UI-Layout/UIMed ...

  10. [bzoj4766] 文艺计算姬 (矩阵树定理+二分图)

    传送门 Description "奋战三星期,造台计算机".小W响应号召,花了三星期造了台文艺计算姬.文艺计算姬比普通计算机有更多的艺 术细胞.普通计算机能计算一个带标号完全图的生 ...