博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
20135202闫佳歆--week4 系统调用(上)--学习笔记
阅读量:5015 次
发布时间:2019-06-12

本文共 2141 字,大约阅读时间需要 7 分钟。

此为个人笔记存档

week 4 系统调用(上)

一、用户态、内核态和中断处理过程

用户通过库函数与系统调用联系起来。

1.内核态

在高执行级别下,代码可以执行特权指令,访问任意的物理地址

2.用户态:

代码的掌控范围受到限制。

intel x86 CPU有四个权限分级,0-3。Linux只取两种,0是内核态,3是用户态

区分权限级别使得系统更加稳定。

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

cs:eip。[代码段选择寄存器:偏移量寄存器]
通过cs寄存器的最低两位,表示当前代码的特权级:
【针对逻辑地址】
0xc0000000以上的空间只能在内核态下访问
0x00000000-0xbfffffff两种状态下都可以访问

如何进行切换?

中断。

3.中断

中断处理是从用户态进入内核态的主要方式。

- 硬件中断  - 系统调用
  1. 寄存器上下文
    从用户态切换到内核态时,必须保存用户态的寄存器上下文到内核堆栈中,同时会把当前内核态的一些信息加载,例如cs:eip指向中断处理程序入口。
    • 用户态栈顶地址
    • 当时状态字
    • 当时cs:eip
    • ……
  2. 中断发生后的第一件事就是保存现场 - SAVE_ALL
    中断处理结束前最后一件事是恢复现场 - RESTORE_ALL

二、系统调用概述

1. 系统调用的意义:

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

- 远离底层硬件编程- 安全性- 可移植性

2. API - 应用编程接口

与系统调用区别:

- API只是一个函数定义- 系统调用是通过软中断向内核发出一个明确的请求。

一般每个系统调用对应一个封装例程,库再用这些封装例程定义出用户的API,方便用户使用。

也就是说,API与系统调用不是一一对应的

API可以:- 直接提供用户态服务- 一个单独的API可能调用几个系统调用- 不同的API可能调用了同一个系统调用

返回值:

- 大部分封装例程返回一个整数 - -1表示失败,不能满足请求  - errno 特定出错码

3.所谓“扒开系统调用的三层皮”

  • API(xyz)
  • 中断向量(system_call)
  • 中断服务程序(sys_xyz)
    enter description here
    1.系统调用的服务例程中,中断向量0x80与system_call绑定起来。(Linux中可以通过执行int $128来执行系统调用。)
    2.system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即系统调用号。
    3.系统调用号将xyz与sys_xyz关联起来。调用号在eax中。

系统调用的参数传递:

  • 函数调用——压栈
  • 用户态到内核态——寄存器传递。
    每个参数长度不能超过32位,个数不能超过6个。
    超过的话?
    使某个寄存器中存储指针,指向内存,内存中存储参数。

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

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

使用time(),代码如下:

#include
#include
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; }

执行如下:

enter description here

2.使用C代码中嵌入汇编代码触发系统调用获取系统当前时间

代码如下:

#include
#include
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; }

可以从中看出用户态向内核态做了什么:

1.传递了一个系统调用号 - eax
2.传递了参数 - ebx

执行如下:

enter description here

转载于:https://www.cnblogs.com/20135202yjx/p/5281209.html

你可能感兴趣的文章
阅读之https及加密原理
查看>>
HDOJ4550 卡片游戏 随便销毁内存的代价就是wa//string类的一些用法
查看>>
css文本样式text、字体样式font
查看>>
python判断图片是否损坏
查看>>
MySQL服务启动:某些服务在未由其他服务或程序使用时将自动停止
查看>>
软件工程第四周作业 - 单元测试
查看>>
KNN与SVM对比&SVM与逻辑回归的对比
查看>>
php 现在拓展地址
查看>>
【Java并发编程】之十六:深入Java内存模型——happen-before规则及其对DCL的分析(含代码)...
查看>>
团队个人冲刺第三天
查看>>
unit
查看>>
2017-10-17 NOIP模拟赛2
查看>>
How to install ia32-libs in Ubuntu 14.04 LTS (Trusty Tahr)
查看>>
ACM/ICPC 之 模拟 (HNUOJ 13391-换瓶模拟)
查看>>
JavaWeb学习——JSP基础
查看>>
Eclipse tomcat server 无法添加项目
查看>>
黑寡妇黄飞鸿
查看>>
leetcode 217 Contains Duplicate 数组中是否有重复的数字
查看>>
The Ctrl & CapsLock `problem'
查看>>
MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作
查看>>