20179223《Linux内核原理与分析》第五周学习笔记
视频内容知识学习
一、用户态、内核态和中断
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 *t
tm为了输出时变成可读的,因为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和工作队列。
20179223《Linux内核原理与分析》第五周学习笔记的更多相关文章
- 20179223《Linux内核原理与分析》第九周学习笔记
视频学习 进程调度与进程调度的时机分析 不同类型的进程有不同的调度需求 第一种分类: --I/O-bound:1.频繁的进行I/O:2.通常会花费很多时间等待I/O操作的完成 --CPU-bound: ...
- 20179223《Linux内核原理与分析》第二周学习笔记
第二周实验 本周学习情况: 学习了X86 cpu的几个寄存器及X86汇编指令: movl %eax,%edx edx=eax %表示一个寄存器,把eax内容放入edx,等号相当于把eax赋值给edx, ...
- 20179223《Linux内核原理与分析》第一周学习笔记
第一周实验 尝试创建两个文件,用通配符查找这两个文件:在创建文件的时候,需要同时创建多个文件的方法运行. 根据作业要求,实现一个lilux命令. 根据作业要求添加一个用户loutest,使用sudo创 ...
- 20179203李鹏举 《Linux内核原理与分析》第一周学习笔记
Linux基础入门 一.Linux的基础学习 1.1 Linux的重要基础操作 Linux不同于Windows的纯粹的图形化界面,虽然也有图形桌面的操作但是更多的操作还是通过命令行来进行,当然除了命令 ...
- 20179223《Linux内核原理与分析》第四周学习笔记
补交第三周作业 完成一个简单的时间片轮转多道程序内核 1.使用实验楼的虚拟机打开shell,用cd LinuxKernel/linux-3.9.4进入linux-3.9.4. 2.执行命令qemu - ...
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- 20169210《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...
- 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业
2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...
- linux内核分析第五周学习笔记
linux内核分析第五周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...
- 2017-2018-1 20179215《Linux内核原理与分析》第二周作业
20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...
随机推荐
- PE文件格式学习之PE头移位
以前刚开始学网络安全,是从免杀开始的.记得那时候杀毒软件还很弱.金山江民瑞星还存在. 那会什么原理也不懂,就一直瞎鼓捣.(后来转入渗透行列了) 这段时间一直在学PE格式,突然想起来以前很古老的PE文件 ...
- iQuery移动端手势事件插件-jGestures
jGestures下载 jGestures事件简介 orientationchange 代表设备顺时针或者逆时针旋转.此事件可以被设备触发,可能使用的是重力传感器. pinch 缩放手势(两个手指在屏 ...
- git tags 管理
新建标签: git tag -a V1.1 -m "some thing" (新建标签前请先commit代码) 推送标签: git push --tags (推送标签前请先推送代码 ...
- 安装 python 数据分析插件 pandas
一上午试验了各种方法,发现利用pycharm是最快的.可以抛弃版本,命令和兼容问题的烦恼.纯粹傻瓜式 方法是 pycharm, 直接在settings里面,搜索pandas,添加即可,他会把所有之前需 ...
- spring mvc: Hibernate验证器(字段不能为空,在1-150自己)
spring mvc: Hibernate验证器(字段不能为空,在1-150自己) 准备: 下载Hibernate Validator库 - Hibernate Validator.解压缩hibern ...
- 设计模式--命令模式C++实现
命令模式C++实现 1定义 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求队列或者记录请求日志,可以提供命令的撤销和恢复功能 2类图 角色描述: Receiver接受者角色,就 ...
- 《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项
<深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面 MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓 ...
- [嵌入式培训笔记]----Linux命令简介
Linux文件系统的结构类似一棵树,是从一个树根生长出来的.树根叫做/.从树根长出很多分叉,就这么一直生长下去.我们使用Linux操作系统的时候总是落在某个分叉上.ls命令可以帮助我们查看当前分叉上所 ...
- Isolation Forest原理总结
Isolation Forest(以下简称iForest)算法是由南京大学的周志华和澳大利亚莫纳什大学的Fei Tony Liu, Kai Ming Ting等人共同提出,用于挖掘异常数据[Isola ...
- Spring入门6事务管理2 基于Annotation方式的声明式事务管理机制
Spring入门6事务管理2 基于Annotation方式的声明式事务管理机制 201311.27 代码下载 链接: http://pan.baidu.com/s/1kYc6c 密码: 233t 前言 ...