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 ...
随机推荐
- HDU 1827 Summer Holiday
http://acm.hdu.edu.cn/showproblem.php?pid=1827 题意: 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家 ...
- @configurationProperties的写法
- 毕业设计总结(1)-canvas画图
去年6月底完成的毕业设计,到现在也才开始给它做个总结,里面有很多可以学习和借鉴的东西. 我的毕业设计的题目是“一种路径规划算法的改进与设计”,具体的要求可参见下面的表格: 题目 一种路径规划算法的改进 ...
- 开发H5游戏引擎的选择:Egret或Laya?
开发H5游戏引擎的选择:Egret或Laya? 一.总结 一句话总结:选laya吧 二.开发H5游戏引擎的选择:Egret或Laya? 一.H5游戏开发的引擎介绍 开发H5游戏的引擎有很多,比如egr ...
- 《Think in Java》(十二)通过异常处理错误
异常虽然简单,但是很有用!学完这一章还是发现 Java 异常还是有很多可学之处的,比如:异常说明,异常链等.
- Web应用体系结构
容器 Servlet没有main()方法,它们受控于另一个Java应用,这个Java应用称为容器(Container).我们最常见的tomcat就是这样一个容器. Web服务器应用(如Apache)得 ...
- Java Applet基础
applet是一种Java程序.它一般运行在支持Java的Web浏览器内.因为它有完整的Java API支持,所以applet是一个全功能的Java应用程序. 如下所示是独立的Java应用程序和app ...
- Eclipse创建Maven聚合项目
整体架构图 1.新建父工程 新建maven父项目(用来管理jar包版本),使子系统使用同一个版本的jar包. File->New->Other->Maven Project,打包方式 ...
- 常数PK系列汇总
常数PK系列说明: 在AC的情况下得分=\(\sum_{i=1}^{10}{1000-runtime\_on\_point_i}\) RE会显示UKE UPD:之前的数据太水,导致好多题都在9000分 ...
- CSU-1307-二分+dij
1307: City Tour Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 59 ...