视频内容知识学习

一、用户态、内核态和中断

1.内核态:处于高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态

2.用户态:处于低的执行级别下,代码只能在级别允许的特定范围内活动。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。

3.Intel x86 CPU有四种不同的执行级别0-3,Linux只使用了其中的0 3级分别表示内核态和用户态。cs寄存器的最低两位表明了当前代码的特权级,00或者11。

4.内核态cs:eip的值是任意的,即可以访问所有的地址空间。用户态只能访问其中的一部分内存地址(0x00000000-0xbbbbbbbf),0xc0000000以上的地址(逻辑地址而不是物理地址)只能在内核态下访问。

5.中断处理是从用户态进入内核态的主要方式,系统调用是一种特殊的中断。从用户态切换到内核态时,中断/int指令会在堆栈上保存用户态的寄存器上下文,其中包括用户态栈顶地址、当时的状态字、当时的cs:eip的值,还有内核态的栈顶地址、内核态的状态字、中断处理程序的入口。中断发生后的第一件事就是保存现场,保存一系列的寄存器的值;中断处理结束前的最后一件事就是恢复现场,退出中断程序,恢复保存寄存器的数据。特别说明: 保护现场:就是进入中断程序,保存需要用到的寄存器的数据;恢复现场:就是退出中断程序,恢复保存寄存器的数据。

二、系统调用

1.系统调用的意义:操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用。把用户从底层的硬件编程中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性

2.操作系统提供的API和系统调用的关系。应用编程接口和系统调用是不同的,API只是一个函数定义,系统调用通过软中断向内核发出一个明确的请求

3.Libc库定义的一些API引用了封装例程(wrapper routine,唯一目的就是发布系统调用)。 一般每个系统调用对应一个封装例程,库再用这些封装例程定义出给用户的API

4.不是每个API都对应一个特定的系统调用。API可能直接提供用户态的服务,如:一些数学函数,一个单独的API可能调用了几个系统调用,不同的API可能调用了同一个系统调用

5.返回值。大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用, -1在多数情况下表示内核不能满足进程的请求,Libc中定义的errno变量包含特定的出错码

6.系统调用的三层皮:xyz、system_call (中断向量)和sys_xyz(中断服务程序)

7.当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。在Linux中是通过执行int$0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常,Intel Pentium II 中引入了sysenter指令(快速系统调用),2.6已经支持(本课程不考虑这个)

8.传参:内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器

9.系统调用也需要输入输出参数,例如:实际的值,用户态进程地址空间的变量的地址,甚至是包含指向用户态函数的指针的数据结构的地址

10.system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。一个应用程序调用fork()封装例程,那么在执行into$0x80之前就把eax寄存器的值置为2(即_NR_fork)。这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号,进入sys_call之后,立即将eax的值压入内核堆栈

11.寄存器传递参数具有如下限制: 1)每个参数的长度不能超过寄存器的长度,即32位 2)在系统调用号(eax)之外,参数的个数不能超过6个(ebx, ecx,edx,esi,edi,ebp) 3)超过6个怎么办?超过6个的话就把某一个寄存器作为一个指针,指向某一块内存。

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



声明了一个time_t tt的变量,struct tm *ttm为了输出时变成可读的,因为tt是int型的数值,通过gcc time.c -o time -m32运行./time就可获得当前的运行时间

四、C代码中嵌入汇编代码的写法



把0赋给eax,add%1指下面输出和输入的部分,“=m”(val3)输出为0,“c”(val1)为1,“d”(val2)为2,“c”指ecx寄存器存储val1的值,把ecx的值赋给eax,%2就是指val2,把它放到edx这个寄存器里面,val1+val2放在eax里面,然后把val1+val2存储的值放到%0,%0就是val3,=m就是写到内存变量里面去,这就实现了val1+val2=val3的功能。

实验

C程序库函数实现系统调用

代码如下:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
int main () {
int ret = 0;
ret = mkdir ("./testdir",0777);
printf ("ret is: %d.\n",ret);
return 0;
}

mkdir函数有两个参数,第一个是待创建的目录名称;第二个是模式,这里设置为0777。

编译成功并执行,在当前目录下生成目录testdir,如图所示

C程序嵌入式汇编实现系统调用

代码如下:

#include <stdio.h>
int main () {
int ret =0;
char *dir = "./testdir";
int mode = 0777;
asm volatile(
"movl $39, %%eax\n\t"
"int $0x80\n\t"
"movl %%eax, %0\n\t"
: “=m”(ret)
:"b"(dir),"c"(mode)
);
printf("ret is: %d.\n",ret);
return 0;
}

编译成功并执行,如图所示

使用汇编实现系统调用的核心知识点有两个:一是如何执行系统调用,二是如果系统调用有参数,如何将参数传给系统调用。

对于使用汇编语言执行系统调用的方法比较简单,只需要将系统调用的编号传给eax寄存器之后,执行int $0x80指令就可以了,对应代码如下:

movl $39, %%eax
int $0x80

对于传参,则需要借助除eax之外的通用寄存器(如:ebx,ecx,edx,csi,cdi),在执行汇编之前将参数依次存入ebc,ecx,....这些通用寄存器即可,对应代码如下

:"b"(dir),"c"(mode)

这里的“b”代表%ebx寄存器,“c”代表%ecx寄存器。需要注意的是,参数顺序一定要和ebx,ecx,....通用寄存器的顺序一致,如果不一致的话程序就无法正确识别参数。如:写成下面这样的话

:"c"(dir),"b"(mode)

虽然编译OK,但在执行的时候会报如下错误

$./a.out
ret is:-14

程序总结

通过对系统调用的两种代码实现方法的分析,我们可以知道C语言的API只不过是对OS底层系统调用的一次封装而已,本质上是通过系统中断实现的。

实验问题

如图所示

在定义char *dir="./testdir1";为什么生成的目录是testdir?如图所示

第7、8章课程学习

1.中断就是由硬件来打断操作系统,中断使得硬件得以发出硬件通知给处理器。

2.中断处理程序与其他内核函数的真正的区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文。中断处理程序是上半部——接收到一个中断,它就立即开始执行,能够被允许稍后完成的工作会推迟到下半部。

3.内核提供的接口包括注册和注销中断处理程序、禁止中断、屏蔽中断线以及检查中断系统的状态。

4.用于延迟Linux内核工作的三种机制:软中断、tasklet和工作队列。

最新文章

  1. 根据地图上的两个点各自的x,y坐标,计算出2点之间的直线距离。显示为公里、米
  2. Android优化——UI优化(四) 使用stytle
  3. ubuntu使用ssh登入不执行.bashrc解决方法
  4. [ActionScript 3.0] as3可以通过CDATA标签声明多行字符串
  5. UVa 12627 (递归 计数 找规律) Erratic Expansion
  6. VB MSFlexGrid 用法
  7. GitBash学习1
  8. Linux入门(15)——Ubuntu16.04安装codeblocks搭建C/C++的IDE环境
  9. Flex读取txt文件中的内容(二)
  10. unity零基础开始学习做游戏(四)biu~biu~biu发射子弹打飞机
  11. SLAM+语音机器人DIY系列:(三)感知与大脑——3.轮式里程计与运动控制
  12. 同一台电脑同时装jdk1.8和jdk1.7
  13. manacher算法,求回文串
  14. oracle实例安装到 4% 不能继续安装
  15. Codeforces.97D.Robot in Basement(bitset 模拟)
  16. 从bios启动说起
  17. silent install oracle 11.2.0.1 x86_64 for linux
  18. CMake: Could NOT find PkgConfig
  19. 洛谷P1186玛丽卡
  20. JavaScript中isPrototypeOf函数

热门文章

  1. 模仿某旅行网站 纯css实现背景放大效果
  2. 机器学习笔记—混合高斯和 EM 算法
  3. ***使用jQuery去封装插件(组件化、模块化的思想),即扩展方法
  4. mysql数据库开放远程连接的方法
  5. IntelliJ IDEA 2017 主题安装及配置
  6. TestNG,多个场景结合运行Suite.xml
  7. ContentPresenter元素
  8. Spring Cloud实战
  9. Nginx 出现413 Request Entity Too Large得解决方法
  10. torch Tensor学习:切片操作