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,其中 ...
随机推荐
- Jmeter_Beanshell解析并提取json响应
1:前置条件 将fastjson-1.2.49.jar包置于jmeter的lib目录下,并将该jar包添加到测试计划的Library中:否则会报:Typed variable declaration ...
- Spring Boot (11) mybatis 关联映射
一对多 查询category中的某一条数据,同时查询该分类下的所有Product. Category.java public class Category { private Integer id; ...
- CAGradientLayer 颜色渐变实现进度条
#import <UIKit/UIKit.h> @interface TJGradientProgressView : UIView /** * 进度值 */ @property(nona ...
- Android开发笔记(11)——DialogFragment & 点击监听
转载请注明:http://www.cnblogs.com/igoslly/p/6931519.html DialogFragment使用 & 点击监听 /* DialogFragment是用于 ...
- Linux通信之同步阻塞模式
[参考]韦东山 教学笔记 1. 原子操作原子操作指的是在执行过程中不会被别的代码路径所中断的操作.常用原子操作函数举例:atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初 ...
- 《java数据结构与算法》系列之“数组"
int arrayName = new int[10] ;2 int arrayLength = arrayName.length; 解释:java有两种数据类型,一种是基本类型,如int等,一种是引 ...
- Eclipse Rap开发 异步刷新UI处理
1.Display.getCurrent()获取的是当前线程的display对象,如果当前在非UI线程中那么获取到的display对象为空: 一般Display.getCurrent() 用 ...
- eclipse快捷键:
打开快捷键提示: ctrl + shift + L; 自动补全代码: Alt + /; 快速修复: ctrl + 1; 导包: ctrl + shift + o; 格式化代码: ctrl + shif ...
- React Native Windows下环境安装(一)
1.安装chocolatey 以管理员权限运行命令提示符(cmd.exe) @powershell -NoProfile -ExecutionPolicy Bypass -Command " ...
- Git 从github克隆文件至本地
学习阶段,同一个项目,如何保障家与公司的代码同步的问题,可以使用git克隆来解决 在家将项目提交到了GitHub上,现在来到公司,需要将GitHub上的项目克隆到本地,那么对于公司的电脑来说,同样需要 ...