中断、异常和系统调用(2-1,2-2,2-3)

2-1 课堂练习2.1:外部中断

本实训分析 Linux 0.11 对外部中断的响应和处理过程。在每条指令执行的末尾,如果没有关中断,CPU 会检查是否收到了外部中断信号,如果有信号,则 CPU 就切换到核心态去执行对应的中断处理程序,在处理完毕后,会执行 iret 这个中断返回指令,回到原状态(一般是用户态),继续执行原程序。

第1关时钟中断的发生

任务描述

 本关任务:通过实际操作回答在输出第一行 0/1 字符的过程中(如下图所示),共发生了几次时钟中断?

相关知识

为了完成本关任务,你需要掌握: 1.设置版本 1 内核为分析对象; 2.开始用 gdb 调试内核; 3.跟踪分析时钟中断。

设置版本1内核为分析对象

首先解压版本1内核源码。使用cp命令将/data/workspace/myshixun/exp1中的1.tgz复制到~/os/目录下;

切换到~/os/linux-0.11-lab目录下,将1.tgz解压到当前目录下;

然后调整cur的指向。先使用rm -rf curcur删除,再使用ln命令创建符号链接。

现在可以编译和测试版本 1 内核。首先进入1/linux目录下编译内核;

确认内核映像文件Image已经生成;

然后回到目录~/os/linux-0.11-lab,并使用./run启动虚拟机检测内核是否正常;

如果正常虚拟机在加载完毕之后将会出现如下画面。

第2关第一次时钟中断

 任务描述

分析版本1内核,找到第一次时钟中断的恢复点地址。

相关知识

为了完成本关任务,你需要掌握: 1.用 gdb 调试内核; 2.跟踪分析时钟中断; 3.中断/异常的恢复点分析。

准备阶段

本关卡的分析对象是版本1内核,可以基于前一关卡环境进行后续实验,如果重置实验环境则需要重新将版本1内核设置为分析对象,详见第一关的相关知识。

使用 gdb 调试内核

启动两个终端,在一个终端里切换到目录~/os/linux-0.11-lab,然后运行脚本 rungdb,以启动 bochs 虚拟机并等待 gdb 连接;

在另一个终端里切换到目录~/os/linux-0.11-lab,然后执行脚本./mygdb,以启动 gdb 并读入符号信息,跟踪到 main 函数入口。

跟踪分析时钟中断

在函数 do_timer(由时钟中断的处理函数 timer_interrupt 调用)处设置断点; 跟踪到该断点第 1 次出现;

中断/异常的恢复点分析

当一个中断/异常被 gdb 捕获时,通常正在运行中断处理程序,这时可以继续跟踪,直至回到恢复点指令。以时钟中断为例,为了从函数 do_timer 跟踪到恢复点,可以如下操作:

由上图可见时钟中断处理程序的入口是 timer_interrupt 函数。 跟踪到当前函数(do_timer)执行完毕返回到 timer_interrupt 函数;

跟踪到 timer_interrupt 函数(用汇编语言写的)末尾的 iret 指令;

通过单步执行命令 si 来执行该 iret 指令,返回到恢复点;

再通过反汇编命令:disas ,分析恢复点指令的地址。

关闭 gdb 调试: 在评测通关之后为了保证环境的正常,不影响下一关的操作,需要先输入 kill 指令关闭虚拟机,然后输入 quit 退出 gdb 调试。

答案

第3关第六次时钟中断

 任务描述

本关任务:通过相关知识以及实验回答:版本 1 内核的第 6 次时钟中断发生时,断点和恢复点(指令地址)分别是多少?此时 bochs 虚拟机输出的 0/1 字符串是什么?(忽略空格)

相关知识

为了完成本关任务,你需要掌握: 1.使用 gdb 调试内核; 2.跟踪分析时钟中断。

准备阶段

本关卡基于前面关卡环境进行后续实验,如果重置实验环境请从第一关重新开始。

使用 gdb 调试内核

启动两个终端,在一个终端里切换到目录~/os/linux-0.11-lab,然后运行脚本 rungdb,以启动 bochs 虚拟机并等待 gdb 连接;

在另一个终端里切换到目录~/os/linux-0.11-lab,然后执行脚本./mygdb,以启动 gdb 并读入符号信息,跟踪到 main 函数入口。

跟踪分析时钟中断

开始用 gdb 调试内核,跟踪到 main 函数入口。方法与第 1 关的步骤(2)一样。 (点击右下角上一关可以直接查看上一关内容,不会对关卡造成影响,但是不要点击评测,会改变环境)

捕获第 6 次时钟中断的发生

方法与第 2 关的步骤(3)类似,跟踪到断点 do_timer 第 6 次出现时即可,此时 jiffies 的值也是 6 。

中断/异常的恢复点分析

当一个中断/异常被 gdb 捕获时,通常正在运行中断处理程序,这时可以继续跟踪,直至回到恢复点指令。以时钟中断为例,为了从函数 do_timer 跟踪到恢复点,可以类似如下操作:

由上图可见时钟中断处理程序的入口是 timer_interrupt 函数。 跟踪到当前函数(do_timer)执行完毕返回到 timer_interrupt 函数;

跟踪到 timer_interrupt 函数(用汇编语言写的)末尾的 iret 指令;

使用调试命令 si 来执行该 iret 指令,返回到恢复点;

然后通过反汇编命令:disas ,来分析恢复点指令的地址。

断点指令和恢复点指令的分析

对于外部中断而言,恢复点指令是断点指令的后一条。需要说明的是,loop 指令的功能是先将 ecx 寄存器减一,然后检查其值,如果其值非 0 ,则继续循环,否则中止循环,执行下一条指令。以如下指令为例:

其功能是:在地址 0x7977 处循环,每次 ecx 寄存器都减一,直到其值为 0 。因此,loop 指令的上一条有可能是它自己。 在 gdb 中查看寄存器值的命令是 info reg:

断点指令和恢复点指令的分析

对于外部中断而言,恢复点指令是断点指令的后一条。需要说明的是,loop 指令的功能是先将 ecx 寄存器减一,然后检查其值,如果其值非 0 ,则继续循环,否则中止循环,执行下一条指令。以如下指令为例:

其功能是:在地址 0x7977 处循环,每次 ecx 寄存器都减一,直到其值为 0 。因此,loop 指令的上一条有可能是它自己。 在 gdb 中查看寄存器值的命令是 info reg:

答案

 

2-2 课后作业2.1:外部中断

第1关修改版本 1 内核源码,使得每次时钟中断发生时,都在屏幕上输出字符 ‘t’

任务描述

本关任务:修改版本 0 内核,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号,如“t(0)”表示0号进程运行时发生了时钟中断。

相关知识

为了完成本关任务,你需要掌握: 1.内核态下的字符输出; 2.判断已经发生了多少次时钟中断。

内核态下的字符输出

在版本 0 内核里,可以使用函数printk来输出字符,其用法类似于printf注: 在版本 0 内核中,没有实现用int 0x81指令输出字符这个功能。

printk用法示例:

  1. printk("trying to free inode with count=%d\n",inode->i_count);
判断已经发生了多少次时钟中断

已经发生的时钟中断的次数记录在全局变量 jiffies 中,每发生一次时钟中断,该变量的值就增加 1 。

编程要求

根据相关知识,以及上课内容,对版本 0 内核进行修改,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号。

,

使用VScode打开1/linux文件夹,获取版本1内核源代码 

在timer_interrupt函数开头添加输出字符t的汇编代码:

movb $116, %al
int $0x81

回到命令行中重新编译1/linux,再启动./rungdb和./mygdb虚拟机即可过关

第2关修改版本 0 内核

任务描述

本关任务:修改版本 0 内核,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号,如“t(0)”表示0号进程运行时发生了时钟中断。

相关知识

为了完成本关任务,你需要掌握: 1.内核态下的字符输出; 2.判断已经发生了多少次时钟中断。

内核态下的字符输出

在版本 0 内核里,可以使用函数printk来输出字符,其用法类似于printf注: 在版本 0 内核中,没有实现用int 0x81指令输出字符这个功能。

printk用法示例:

  1. printk("trying to free inode with count=%d\n",inode->i_count);
判断已经发生了多少次时钟中断

已经发生的时钟中断的次数记录在全局变量 jiffies 中,每发生一次时钟中断,该变量的值就增加 1 。

编程要求

根据相关知识,以及上课内容,对版本 0 内核进行修改,使得每发生 100 次时钟中断,就在屏幕上输出一个字符‘t’和当时的进程号。

,

通过vscode找到do_timer

 在函数中添加

if(jiffies%100==0)
prink("t(%d),sys_getpid());

2-3 课堂练习2.2:中断/异常的处理过程


第1关除零异常分析

任务描述

分析版本 1.1 内核,回答下列问题: 1.在函数 main 的语句jiffies = jiffies/0;所对应的汇编指令片段中,有一个 idiv 指令,此指令的地址是多少? 2.在该 idiv 指令执行之前,当前指令位置(CS:EIP)和栈位置(SS:ESP)分别是多少? 3.使用 si 命令执行了该指令后,新指令位置和栈位置分别是多少?此时栈中保存的恢复点位置和用户栈位置分别是多少?

相关知识

为了完成本关任务,你需要掌握: 1.如何设置某版本的内核为分析对象; 2.如何开始用 gdb 调试内核; 3.查看 C 语句编译之后对应的汇编指令片段; 4.分析响应中断/异常时,CPU 做了哪些工作; 5.查看当前寄存器的状态; 6.查看当前栈顶的状态。

实验准备

本关卡使用版本 1.1 内核作为分析对象,内核文件存放在/data/workspace/myshixun/exp1文件夹中,可以将其解压到linux-0.11-lab下使用。

如何设置某版本的内核为分析对象

下面以版本1内核为例进行讲解。

首先解压版本1内核源码。使用cp命令将/data/workspace/myshixun/exp1中的1.1.tgz复制到~/os/目录下;

切换到~/os/linux-0.11-lab目录下,将1.1.tgz解压到当前目录下;

然后调整cur的指向。先使用rm -rf curcur删除,再使用ln命令创建符号链接。

如何开始用 gdb 调试内核

先关闭bochs虚拟机,然后打开两个终端,其中一个终端在linux-0.11-lab目录下运行rungdb脚本,以启动 bochs 虚拟机并等待 gdb 连接;

在另一个终端里切换到目录~/os/linux-0.11-lab/,然后启动脚本./mygdb,这个命令会启动 gdb 并读入内核符号信息,同时会通过执行0.gdb中的调试命令来连接到 bochs 虚拟机,并进而跟踪到 main 函数入口。

查看 C 语句编译之后对应的汇编指令片段

如果要查看某条 C 语句编译之后对应的汇编指令片段,可以在该 C 语句处设置断点,并跟踪到该断点,然后反汇编,所看到的当前指令之后的一段汇编指令就对应于该 C 语句。

例如,jiffies = jiffies/0;是文件 main.c 的第 147 行,可以如下方式查看:

上面显示的汇编指令中,有一行前面有箭头标识,此即为当前指令,即马上将要执行的指令。

分析响应中断/异常时,CPU 做了哪些工作
  • 切换到核心栈,并在其中保存中断现场。

  • 转到中断处理程序去运行,并切换到核心态。

如下图所示:

上图显示了栈中中断现场的结构,(OLD SS:OLD ESP) 描述了用户栈顶的位置,(OLD CS:OLD EIP) 描述了恢复点的位置。

如何查看当前寄存器的状态

使用 gdb 调试命令 info registers 即可,如下所示:

也可以单独查看某一个寄存器:

如何查看当前栈顶的状态

可以使用命令 x 来查看:

上面显示了栈顶的 5 个长字,是某异常发生时的中断现场,其中存储的用户栈顶的位置是 0x17:0x2573c ,存储的恢复点的位置是 0xf:0x7967 。需要注意的是,x86 中栈是从高地址向低地址方向增长的,这里的栈顶位置是 0x1fa0c 。

编程要求

根据相关知识,回答问题:(将答案填写在/data/workspace/myshixun/第一关.txt中) 1.在函数 main 的语句jiffies = jiffies/0;所对应的汇编指令片段中,有一个 idiv 指令,此指令的地址是多少? 2.在该 idiv 指令执行之前,当前指令位置(CS:EIP)和栈位置(SS:ESP)分别是多少? 3.使用 si 命令执行了该指令后,新指令位置和栈位置分别是多少?此时栈中保存的恢复点位置和用户栈位置分别是多少?

答案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/207408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DHTMLX Scheduler PRO 6.0.5 Crack

功能丰富的 JavaScript调度程序 DHTMLX Scheduler 是一个 JavaScript 日程安排日历,具有 10 个视图和可定制的界面,用于开发任何类型的日程安排应用程序。 DHTMLX JS 调度程序库的主要特性 我们的 JS 调度程序最需要的功能之一是时间轴视图。借助时间轴…

【语义分割数据集】——imagenet语义分割

地址:https://github.com/LUSSeg/ImageNet-S 1 例图 2. 类别和数量信息 疑问 根据原文的描述:Based on the ImageNet dataset, we propose the ImageNet-S dataset with 1.2 million training images and 50k high-quality semantic segmentation annot…

【JNPF】好用、高性价比的低代码开发平台

目录 1.JNPF介绍 突出优势 2.JNPF的开放性与扩展性 平台的开放性: 平台高拓展性 在快速发展的软件开发领域,低代码平台已经成为了一种重要的开发方法,它使非专业开发人员也能够参与到软件开发中去,大大加速了软件开发的效率。…

Leetcode—2034.股票价格波动【中等】

2023每日刷题&#xff08;五十二&#xff09; Leetcode—2034.股票价格波动 算法思想 实现代码 class StockPrice { public:int last 0;multiset<int> total;unordered_map<int, int> m;StockPrice() {}void update(int timestamp, int price) {if(m.count(time…

VUE学习一、环境的安装

1.node.js安装 node.js是前端依赖的环境, 类似于java中的jdk 下载地址 node.js 下载 msi文件 下完就是一顿嘎嘎安装 , 安装后可以cmd看看node和npm的版本 1.2 yarn的安装 Yarn是Facebook最近发布的一款依赖包安装工具。Yarn是一个新的快速安全可信赖的可以替代NPM的依赖管…

计算机图形学——消隐算法

目录 消隐算法 &#xff08;1&#xff09;隐藏线消除算法 &#xff08;2&#xff09;隐藏面消除算法 曲面体消隐算法 3D Mesh 隐藏面消除算法 &#xff08;1&#xff09;深度缓冲器算法&#xff08;zBuffer&#xff09; 深度缓冲器 &#xff08;2&#xff09;深度排序…

SpringBoot的监控(Actuator) 功能

目录 0、官方文档 一、引入依赖 二、application.yml文件中开启监控 三、具体使用 四、具体细节使用 五、端点开启与禁用 六、定制Endpoint 1. 定制 /actuator/health 2. 定制 /actuator/info &#xff08;1&#xff09;直接在配置文件中写死 &#xff08;2&#xff…

如何进行代码混淆?方法与常见工具介绍

​ 目录 什么是代码混淆&#xff1f; 代码混淆的方法 常见代码混淆工具 什么是代码混淆&#xff1f; 代码混淆是指将计算机程序的代码转换成一种功能上等价&#xff0c;但难于阅读和理解的形式的行为。混淆后的代码很难被反编译&#xff0c;即使反编译成功也很难得出程序的…

【Linux系统化学习】命令行参数 | 环境变量的再次理解

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 代码仓库&#xff1a;Gitee 目录 mian函数传参获取环境变量 手动添加环境变量 导出环境变量 environ获取环境变量 本地变量和环境变量的区别 Linux的命令分类 常规命令 内建命令 …

js获取快递单号小练习

目录 1、css代码 2、html代码 3、js代码 完整代码 效果图 1、css代码 .box{width: 400px;height: 300px;margin: 100px auto;position: relative;}input{width: 250px;height: 40px;outline: none;}span{display: block;position: absolute;min-width: 270px;max-width: 40…

pytest +uiautomator2+weditor app自动化从零开始

目录结构1.0 把设备连接单独移出去了 模块操作代码&#xff0c;有一些流程操作和断言方法 from devices import dv from time import sleep import random from tool.jt import capture_screenshotdef initialization(func):def wrapper():sleep(1)dv.app_stop(com.visteon.…

CSS特效025:旋转的loading状态

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS…

Linux学习笔记(九)MISC设备驱动

前言 misc 的意思是混合、杂项的&#xff0c;因此 MISC 驱动也叫做杂项驱动。也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动&#xff0c;通常嵌套在 platform 总线驱动中&#xff0c;实现复杂的驱动&#xff0…

Mysql 索引概念回顾

一、什么是索引 在关系数据库中&#xff0c;索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构&#xff0c;它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录&#xff0c;可以根据…

《算法竞赛进阶指南》------图论篇

文章目录 0x01 Telephone Lines POJ - 36620x02 P1073 [NOIP2009 提高组] 最优贸易0x03 道路和航线 BZOJ22000x04 Sorting It All Out POJ - 1094 topo0x05 Sightseeing trip POJ - 1734 最小环问题0x06 Cow Relays POJ - 3613 S到E经过k条边的最短路0x07 走廊泼水节 &#xff…

为什么Java程序员需要掌握多线程?揭秘并发编程的奥秘

为什么Java程序员需要掌握多线程&#xff1f;揭秘并发编程的奥秘 个人简介前言多线程对于Java的意义&#x1f4cc;1.提高程序性能&#xff1a;&#x1f4cc;2 提高用户体验&#xff1a;&#x1f4cc;3支持并发处理&#xff1a;&#x1f4cc;4 资源共享和同步&#xff1a;&#…

C# 语法笔记

1.ref、out&#xff1a;参数传递的两种方式 ref&#xff1a;引用传递 using System; namespace CalculatorApplication {class NumberManipulator{public void swap(ref int x, ref int y){int temp;temp x; /* 保存 x 的值 */x y; /* 把 y 赋值给 x */y temp; /* 把 t…

Python中的range()函数详解:掌握迭代的利器

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python中的range()函数是一个强大的工具&#xff0c;用于生成一系列的数字&#xff0c;常用于循环操作。虽然看似简单&#xff0c;但其灵活性和功能却不容小觑。在本文中&#xff0c;将深入研究range()函数&…

docker容器_自定义上传jenkins镜像(Dockerfile实现)

1.创建jenkins目录&#xff0c;并上传相应的包 mkdir /jenkins/ 2.创建一个Dockerfile文件 FROM daocloud.io/library/centos:7#把当前目录下的jenkins.war包传到内部容器的/ 下 ADD ./jenkins.war /#把当前目录下的jdk传到内部容器的/opt/,并解压 ADD ./jdk-11.0.19_linu…

网络编程基础api

1. IP 协议 1.1 IP 分片 &#xff08;1&#xff09;IP 分片和重组主要依靠 IP 头部三个字段&#xff1a;数据报标识、标志和片偏移 以太网帧的 MTU 是 1500 字节&#xff1b; 一个每个分片都有自己的 IP 头部&#xff0c;它们都具有相同的标识值&#xff0c;有不同的片偏移…