Linux系统调用具体解释(怎样从用户空间进入内核空间)
系统调用概述
计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同一时候执行的多个进程都须要訪问这些资源,为了更好的管理这些资源进程是不同意直接操作的,全部对这些资源的訪问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(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查找)
- #ifndef _ASM_X86_UNISTD_32_H
- #define _ASM_X86_UNISTD_32_H
- /*
- * This file contains the system call numbers.
- */
- #define __NR_restart_syscall 0
- #define __NR_exit 1
- #define __NR_fork 2
- #define __NR_read 3
- #define __NR_write 4
- #define __NR_open 5
所以详细调用fork的过程是:将2存入%eax中,然后进行系统调用,伪代码:
- mov eax, 2
- int 0x80
对于參数传递,Linux是通过寄存器完毕的。Linux最多同意向系统调用传递6个參数,分别依次由%ebx,%ecx,%edx,%esi,%edi这5个寄存器完毕,须要6个及以上參数情况不多见。另外应该有一个单独的寄存器存放指向全部这些參数在用户空间的地址的指针。给用户空间的返回值通过eax寄存器传递。比方,调用exit(1),伪代码是:
- mov eax, 2
- mov ebx, 1
- int 0x80
由于exit须要一个參数1,所以这里仅仅须要使用ebx。这6个寄存器可能已经被使用,所以在传參前必须把当前寄存器的状态保存下来,待系统调用返回后再恢复,这个在后面栈切换再详细讲。
Linux中,在用户态和内核态执行的进程使用的栈是不同的。分别叫做用户栈和内核栈,两者各自负责对应特权级别状态下的函数调用。当进行系统调用时。进程不仅要从用户态切换到内核态。同一时候也要完毕栈切换。这样处于内核态的系统调用才干在内核栈上完毕调用。系统调用返回时,还要切换回用户栈,继续完毕用户态下的函数调用。
寄存器%esp(栈指针。指向栈顶)所在的内存空间叫做当前栈,比方%esp在用户空间则当前栈就是用户栈。否则是内核栈。栈切换主要就是%esp在用户空间和内核空间间的来回赋值。
在Linux中,每一个进程都有一个私有的内核栈,当从用户栈切换到内核栈时,需完毕保存%esp以及相关寄存器的值(%ebx。%ecx...)并将%esp设置成内核栈的对应值。
而从内核栈切换会用户栈时。须要恢复用户栈的%esp及相关寄存器的值以及保存内核栈的信息。一个问题就是用户栈的%esp和寄存器的值保存到什么地方,以便于恢复呢?答案就是内核栈,在调用int指令机型系统调用后会把用户栈的%esp的值及相关寄存器压入内核栈中。系统调用通过iret指令返回。在返回之前会从内核栈弹出用户栈的%esp和寄存器的状态。然后进行恢复。
相信大家一定听过说,系统调用非常耗时。要尽量少用。通过上面描写叙述系统调用的实现原理,大家也应该知道这当中的原因了。
第一,系统调用通过中断实现,须要完毕栈切换。
第二,使用寄存器传參,这须要额外的保存和恢复的过程。
上面关于系统调用的阐述,如有错误欢迎指正。。
Linux系统调用具体解释(怎样从用户空间进入内核空间)的更多相关文章
- Linux用户空间与内核空间(理解高端内存)
Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...
- Linux用户空间与内核空间
源:http://blog.csdn.net/f22jay/article/details/7925531 Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针 ...
- linux 用户空间与内核空间——高端内存详解
摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对 ...
- linux用户空间和内核空间(内核高端内存)_转
转自:Linux用户空间与内核空间(理解高端内存) 参考: 1. 进程内核栈.用户栈 2. 解惑-Linux内核空间 3. linux kernel学习笔记-5 内存管理 Linux 操作系统和驱 ...
- Linux用户空间与内核空间(理解高端内存)【转】
转自:http://www.cnblogs.com/wuchanming/p/4360277.html Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递 ...
- 在Linux用户空间做内核空间做的事情
导读 我相信,Linux 最好也是最坏的事情,就是内核空间(kernel space)和用户空间(user space)之间的巨大差别.如果没有这个区别,Linux 可能也不会成为世界上影响力最大的操 ...
- Linux内存管理--用户空间和内核空间【转】
本文转载自:http://blog.csdn.net/yusiguyuan/article/details/12045255 关于虚拟内存有三点需要注意: 4G的进程地址空间被人为的分为两个部分--用 ...
- linux内存管理--用户空间和内核空间
关于虚拟内存有三点需要注意: 4G的进程地址空间被人为的分为两个部分--用户空间与内核空间.用户空间从0到3G(0xc0000000),内核空间占据3G到4G.用户进程通常情况下只能访问用户空间的虚拟 ...
- 如何看待Linux操作系统的用户空间和内核空间
作为中央核心处理单元的CPU,除了生产工艺的不断革新进步外,在处理数据和响应速度方面也需要有权衡.稍有微机原理基础的人都知道Intel X86体系的CPU提供了四种特权模式ring0~ring3,其中 ...
随机推荐
- BZOJ 3727 DP?推式子..
思路: 设$sum[i]表示i的子树中a[i]的和$ $b[1]=\Sigma a[i]*dis[i] = \Sigma _{i=2} ^n sum[i]$ $b[x]-b[fa[x]]=sum[1] ...
- 安装sql server 2008 R2出现 创建usersettings/microsoft.sqlserver.configuration.landingpage.properties.setter
造成这个原因是由于先装了VS(我之前安装的是vs2012)开发环境造成的,需要删除 路径为 C:\Users\Administrator\AppData\Local\Microsoft_Corpora ...
- 【Linux】七种文件类型
Linux中的七种文件类型 d 目录文件. l 符号链接(指向另一个文件). s 套接字文件. b 块设备文件,二进制文件. c 字符设备文件. p 命名管道文件. - 普通文件
- Python 遍历目录
代码: 1.递归使用遍历目录 import os def scanfile(path): filelist = os.listdir(path) allfile = [] for filename i ...
- hexo搭建博客
在使用hexo搭建个人博客的时候,修改.yml文件后出现错误:FATAL can not read a block mapping entry; a multiline key may not be ...
- Python基础知识-Day4
一.函数关键字关键字是Python内置的,具有特殊意义的标识符,自定义标识符命名时不可与之重复.可以通过以下代码查看Python内置的关键字内容. import keyword print(keywo ...
- Html 页面刷新后出现闪动
Html 页面刷新后,或跳转后,出现闪动,抖动问题 1.查看有没有用到新字体,新字体链接位置是否存在 如: @font-face { font-family: "AvantGarde-Dem ...
- Hexo系列(一) 搭建博客网站
写在前面的话:本系列文章主要参考 Hexo官方说明文档,同时结合自己在使用过程中的一些心得体会,撷取下来,和大家分享分享.好,下面闲话不多说,马上开始我们的 Hexo 之旅吧 温馨提醒:博主使用的操作 ...
- Bootstrap 表单控件状态(禁用状态)
Bootstrap框架的表单控件的禁用状态和普通的表单禁用状态实现方法是一样的,在相应的表单控件上添加属性“disabled”.和其他表单的禁用状态不同的是,Bootstrap框架做了一些样式风格的处 ...
- git常见问题总结
1.每次上传文件的时候,有很多iml文件容易不小心上传上去,然后报错,所以可以把这些文件取消上传 如图所示,每次提交时,都不会显示标红文件 具体操作步骤如下: