LINUX内核分析第四周——扒开系统调用的三层皮
LINUX内核分析第四周——扒开系统调用的三层皮
李雪琦 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、用户态、内核态和中断处理过程
1. 用户态和内核态
CPU指令执行级别:
执行特权指令,访问任意的物理地址——内核态。
低级别:代码只能在级别允许的特定范围内活动——用户态。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。
Intel x86 CPU有四种不同的执行级别0~3,Linux只用其中的0和3来表示内核态和用户态。
区分内核态和用户态:CPU每条指令的读取都是通过cs:eip,cs寄存器最低两位表明了当前代码的特权级。
内核态下可访问所有地址空间。
0xc0000000(逻辑地址)以上的空间只能在内核态下访问。
0x00000000 ~ 0xbfffffff 内核态和用户态均可访问。
用户态转换为内核态的主要方式:中断。
2. 中断处理
- 用户态到内核态的切换:必须保存用户态的寄存器上下文,包括用户态栈顶地址、当时的状态字、cs:eip的值,以及内核态的栈顶地址、当时的状态字、中断处理程序入口。
- 中断发生后的第一件事:保存现场(SAVE_ALL:保存需要用到的寄存器数据)。
- 中断处理结束前的最后一件事:恢复现场(RESTORE_ALL:退出中断程序,恢复保存寄存器的数据)。
二、系统调用概述
1. 系统调用的意义:
操作系统为用户态进程与硬件设备进行交互提供了一组接口,就是系统调用。
- 远离底层硬件编程
- 安全性
- 可移植性
2. API - 应用编程接口
与系统调用区别:
- API只是一个函数定义。
- 系统调用是通过软中断向内核发出一个明确的请求。
- 一般每个系统调用对应一个封装例程,库再用这些封装例程定义出用户的API,方便用户使用。也就是说,API与系统调用不是一一对应的。
API可以:
- 直接提供用户态服务
- 一个单独的API可能调用几个系统调用
- 不同的API可能调用了同一个系统调用
返回值:
- 大部分封装例程返回一个整数
- -1表示失败,不能满足请求
- errno 特定出错码
3.所谓“扒开系统调用的三层皮”
- API(xyz)
- 中断向量(system_call)
- 中断服务程序(sys_xyz)
1.系统调用的服务例程中,中断向量0x80与system_call绑定起来。(Linux中可以通过执行int $128来执行系统调用。)
2.system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即系统调用号。
3.系统调用号将xyz与sys_xyz关联起来。调用号在eax中。
系统调用的参数传递:
- 函数调用——压栈
- 用户态到内核态——寄存器传递。
每个参数长度不能超过32位,个数不能超过6个。
超过的话,使某个寄存器中存储指针,指向内存,内存中存储参数。
三、使用库函数API和C代码中嵌入汇编代码触发同一个系统调用
1.使用库函数API获取系统当前时间
使用time(),代码如下:
#include<stdio.h>
#include<time.h>
int main()
{
time_t tt;
struct tm *t;//构造一个结构体,方便读取
tt = time(NULL);//time系统调用
t = localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d\n", t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
return 0;
}
2.使用C代码中嵌入汇编代码触发系统调用获取系统当前时间
代码如下:
#include<stdio.h>
#include<time.h>
int main()
{
time_t tt;
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t" # 把ebx清零,相当于传参数
"mov $0xd,%%eax\n\t"# 把0xd放入eax中,即系统调用号13,指time
"int $0x80\n\t"
"mov %%eax,%0\n\t" # 返回值是在eax中,%0指tt,把返回值放到tt中去。
: "=m" (tt)
);
t = localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d\n", t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
return 0;
}
四、使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
在这里我选择的是第7号系统调用,waitpid。
1.使用库函数API:

2.嵌入汇编:

3.运行结果:

五、总结
- 即便是最简单的程序,在进行输入输出等操作时也会需要调用操作系统所提供的服务,也就是系统调用。
- Linux下的系统调用是通过中断(int 0x80)来实现的。
- 在执行int 80指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值可以在寄存器 eax 中获得。
- Linux 采用的是 C 语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。
LINUX内核分析第四周——扒开系统调用的三层皮的更多相关文章
- 20135327郭皓--Linux内核分析第四周 扒开系统调用的三层皮(上)
Linux内核分析第四周 扒开系统调用的三层皮(上) 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/U ...
- linux内核分析 第四周 扒开系统调用的三层皮(上)
一.用户态.内核态和中断处理过程 系统调用是用户通过库函数方式:库函数帮我们把系统调用封装起来. 内核态:高级别执行,可以使用特权指令,访问任意的物理地址. 用户态:低级别执行,代码范围受到限制. C ...
- Linux内核分析 笔记五 扒开系统调用的三层皮(下) ——by王玥
(一)给MenuOs增加time和time-asm命令 更新menu代码到最新版 在main函数中增加MenuConfig 增加对应的Ttime和TimeAsm函数 make rootfs (二)使用 ...
- Linux内核及分析 第四周 扒开系统调用的三层皮(上)
实验过程 选择20号系统调用getpid(取得进程识别码) 在网上查询getpid函数的C语言代码以及其嵌入式汇编语句 C语言代码: #include <stdio.h> #include ...
- Linux内核设计第四周——扒开系统调用三层皮
Linux内核设计第四周 ——扒开系统调用三层皮 一.知识点总结 (一).系统调用基础知识 1.用户态和内核态 内核态:在高级别的状态下,代码可以执行特权指令,访问任意的物理地址: 用户态:在相应的低 ...
- 《Linux内核分析》第四周 扒开系统调用的“三层皮”
[刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK FOUR( ...
- linux 内核 第四周 扒开系统调用的三层皮 上
姬梦馨 原创作品 http://mooc.study.163.com/course/USTC-1000029000 一.用户态.内核态和中断处理过程 用户通过库函数与系统调用联系起来:库函数帮我们把系 ...
- Linux内核分析——第四周学习笔记20135308
第四周 扒开系统调用的“三层皮” 一.内核.用户态和中断 (一)如何区分用户态.内核态 1.一般现在的CPU有几种不同的指令执行级别 ①在高级别的状态下,代码可以执行特权指令,访问任意的物理地址,这种 ...
- LINUX内核分析第四周学习总结——扒开系统调用的“三层皮”
LINUX内核分析第四周学习总结--扒开系统调用的"三层皮" 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC ...
随机推荐
- 自己通过Cygwin编译的windowsx86下的更新至4.0.1
采用方法:https://my.oschina.net/maxid/blog/186506 方法中在3.2.6未找到src/redis.h文件 未修改 方法中 /deps/hiredis/net.c ...
- Charles的安装与破解
Charles启动需要安装java环境,不知配置了jdk就可以,而是需要java环境,否则下载后点击启动会提示找不到suitable java 1 安装java环境 安装java环境是在https:/ ...
- Linux 安装FastDFS<单机版>(使用Mac远程访问)
阅读本文需要先阅读安装FastDFS<准备> 一 编译环境 yum install gcc-c++ yum -y install libevent yum install -y pcre ...
- 【springmvc+mybatis项目实战】杰信商贸-7.生产厂家新增
我们要实现新的功能,就是生产厂家的新增先来回顾一下系统架构图我们数据库这边已经建好表了,接下来要做的就是mapper映射 编辑FactoryMapper.xml文件,加入“添加”的逻辑配置代码块 &l ...
- 基础的Servlet
1.认识Servlet 今天接触了Servlet,我就写了这篇Servlet的文章.首先,我们了解一下Servlet是什么: 这是百度百科的解释,我个人理解是可以用来前后端交互的一个东西,例如可以实现 ...
- 选题博客:北航iCourse课程信息平台
1. 用户调查 在选题的时候,我们面向北航所有本科在读本科生,发布了<北航信息平台用户调查>.此次问卷调查共回收有效问卷95份. 1.1 功能需求调查 调查其中一项是让同学们对平台功能进行 ...
- 【线段树维护复杂状态】Ryuji doesn't want to study
https://nanti.jisuanke.com/t/31460 tree[rt].ans = tree[rt << 1].ans + tree[rt << 1 | 1]. ...
- EXT4.1表单提交(非AJAX)
Ext.require([ 'Ext.form.*', 'Ext.data.*' ]); Ext.onReady(function(){ Ext.apply(Ext.form.VTypes, { re ...
- HDU 5642 King's Order dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5642 King's Order Accepts: 381 Submissions: 1361 ...
- C++中使用内存映射文件处理大文件
引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...