系统调用(上)

谈愈敏 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

用户态、内核态和中断

系统调用是用户通过库函数方式:库函数帮我们把系统调用封装起来。

用户态&内核态(CPU执行级别)
  • 内核态:高级别执行,可以使用特权指令,访问任意的物理地址。对应x86 0级
  • 用户态:低级别执行,代码范围受到限制。对应x86 3级(x86CPU有0-3四个级别)

这种权限级别划分让系统更稳定。

如何区分用户态&内核态?

地址空间是显著标识,cs:eip[代码段选择寄存器:偏移量寄存器](指令地址)

  • 0xc0000000以上的地址只能在内核态下访问
  • 0x00000000-0xbfffffff两种状态都行

注意:这里指逻辑地址(进程地址空间)而不是物理地址

另:cs寄存器的最低两位,表示当前代码的特权级

中断处理是从用户态进入内核态主要的方式
  • 从用户态进入内核态:必须保存用户态的寄存器上下文
  • 中断/int指令在堆栈上保存寄存器的值:用户态/内核态栈顶地址(ss:esp)、状态字(eflags)、cs:eip值(内核态时指向中断服务程序入口)

系统调用是一种特殊的中断

中断发生后第一件事就是保存现场:

进入中断程序,保存寄存器数据
SAVE_ALL

中断结束前最后一件事就是恢复现场:

退出中断程序,恢复寄存器数据
RESTORE_ALL
iret(pop cs:eip/ss:esp/eflags from kernel stack)
#对应着中断信号或int指令,与发生时CPU动作相反

系统调用概述

系统调用的意义

操作系统为用户态进程与硬件设备进行交互提供了一组接口-系统调用

  • 用户不管硬件编程
  • 提高系统安全性
  • 用户程序可移植
API和系统调用
  • API:应用编程接口,是一个函数定义
  • 系统调用:通过软中断向内核发出明确请求

Libc库定义的一些API引用了封装例程(唯一目的就是发布系统调用)

  • 一般每个系统调用对应一个封装例程
  • 库用封装例程定义出给用户的API

不是每个API都对应一个特定的系统调用

  • API可直接提供用户态服务,如数学函数
  • 一个API可调用几个系统调用
  • 不同API可调用同一系统调用

返回值

  • 封装例程返回一个整数,含义依赖与相应系统调用
  • -1表示内核不能满足进程的要求
  • Libc定义的errno变量包含特定出错码
应用程序、封装例程、系统调用处理程序、系统调用服务例程之间的关系

xyz是一个函数,即API
应用程序编程接口里封装了一个系统调用,触发一个中断:中断向量0x80对应内核代码系统调用起点system_call
中断服务程序(sys_xyz)

系统调用三层皮:

  • API(xyz)
  • 中断向量(system_call)
  • 中断服务程序(sys_xyz)

用户态进程调用系统调用时,CPU切换到内核态执行内核函数(Linux中通过执行int $128来执行系统调用,产生向量为128的编程异常)

传参:进程指明需要哪个系统调用,传递系统调用号,使用eax传递

  • 系统调用号将xyz与sys_xyz关联起来
  • system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即系统调用号。

寄存器传递参数的限制:

  • 每个参数长度不能超过寄存器长度即32位
  • 在系统调用号eax之外,个数不能超过6个

超过6的话:某个寄存器中存储指针,指针会指向一个地址空间,存储参数。

使用库函数API和C代码中嵌入汇编代码触发同一个系统调用

使用库函数API获取系统当前时间

使用time():

#include<stdio.h>
#include<time.h> int main()
{
time_t tt;
struct tm *t;//构造一个结构体,将tt转换为这个方便读取时间的
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;
}

编译:gcc time.c -o time -m32

使用C代码中嵌入汇编代码触发系统调用获取系统当前时间
#include<stdio.h>
#include<time.h> int main()
{
time_t tt;
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t" //把ebx清零,系统调用传递第一个参数用ebx,这里是NULL
"mov $0xd,%%eax\n\t"//把0xd放入eax中,即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;
}

这段代码让我们更清楚的知道用户态进程对内核态做了什么

  • 传递了一个系统调用号 - eax
  • 传递了参数 - ebx

实验

选择20号系统调用getpid来获取进程ID

使用库函数API获取系统当前进程ID

代码:

运行:

使用C代码中嵌入汇编代码触发系统调用获取系统当前进程ID

思想:和视频示例中类似,只是传递给eax的系统调用号为0x14,即20号系统调用getpid。

代码:

运行:

20135220谈愈敏Blog4_系统调用(上)的更多相关文章

  1. 20135220谈愈敏Blog5_系统调用(下)

    系统调用(下) 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 给Me ...

  2. 20135220谈愈敏Blog8_进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-100002 ...

  3. 20135220谈愈敏Blog7_可执行程序的装载

    可执行程序的装载 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. ...

  4. 20135220谈愈敏Blog3_构造一个简单的Linux系统MenuOS

    构造一个简单的Linux系统MenuOS 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1 ...

  5. 20135220谈愈敏Blog6_进程的描述和创建

    进程的描述和创建 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 进程 ...

  6. 20135220谈愈敏Blog2_操作系统是如何工作的

    操作系统是如何工作的 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计 ...

  7. 20135220谈愈敏Linux_总结

    Linux_总结 具体博客链接 计算机是如何工作的 操作系统是如何工作的 构造一个简单的Linux系统MenuOS 系统调用(上) 系统调用(下) 进程的描述和创建 可执行程序的装载 进程的切换和系统 ...

  8. 20135220谈愈敏Linux Book_4

    进程调度 进程:程序的运行态表现形式 进程调度程序:确保进程能有效工作的一个内核子系统,决定将哪个进程投入运行.何时运行以及运行多长时间,在可运行态进程之间分配有限的处理器时间资源. 最大限度的利用处 ...

  9. 20135220谈愈敏Linux Book_3

    第3章 进程管理 进程是Unix操作系统抽象概念中最基本的一种,进程管理是操作系统的心脏所在. 3.1 进程 进程:处于执行期的程序以及相关的资源的总称. 线程:在进程中活动的对象,拥有独立的程序计数 ...

随机推荐

  1. BZOJ2502:清理雪道(有上下界最小流)

    Description        滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时 ...

  2. docker 1.13.1 启动容器过程中mount报错

    docker 1.13.1 启动container 问题 [root@openfalcon_transfer1 harbor]# docker run -it --name test busybox ...

  3. 2018.4.26 Mac安装Redis5.0.3版本服务器

    Mac安装Redis服务器 安装 1.到官网下载 选择稳定版本 打开官网:https://redis.io/ 2.下载完成后,打开命令行工具,执行解压命令 tar zxvf redis-5.0.3.t ...

  4. 封装PDO连接数据库代码

    废话不说直接上代码: <?php class DB { protected static $_connect; protected $dsn, $pdo; protected $_data, $ ...

  5. NodeHandles

    os::NodeHandle类有两个作用: 第一.它在roscpp程序内提供了一种RAII(Resource Acquisition Is Initialization)类型式启动和关闭内部节点的方法 ...

  6. scapy学习笔记(4)简单的sniffing 嗅探

    转载请注明:@小五义:http://www.cnblogs/xiaowuyi 利用sniff命令进行简单的嗅探,可以抓到一些简单的包.当不指定接口时,将对每一个接口进行嗅探,当指定接口时,仅对该接口进 ...

  7. jqgrid 配置分页大小及下拉项

    如何配置分页大小的下拉项?显示效果如下: 通过 rowNum 来设置默认分页大小 通过 rowList 来设置分页下拉.   rowList 的值为一个数组,比如:[10,20,30] $(" ...

  8. R语言的数据输入

    既然了解了R语言的基本数据类型,那么如何将庞大的数据送入R语言进行处理呢?送入的数据又是如何在R语言中进行存储的呢?处理这些数据的方法又有那些呢?下面我们一起来探讨一下. 首先,数据输入最直接最直观的 ...

  9. 20155216 Exp8 WEB基础实践

    Exp8 WEB基础实践 实践内容 Apache环境配置 apache是kali下的web服务器,通过访问 ip地址+端口号+文件名称 打开对应的网页. 输入命令 vi /etc/apache2/po ...

  10. Luogu P1198 [JSOI2008]最大数

    我会用高级(???)的单调栈来打这道题吗? 线段树即可水过. 假设这个数列刚开始所有数都是0,然后我们每次只要进行一个点的修改和区间求和即可. 这不就是 线段树大法. 只要用一个len记录一下当前数列 ...