以下实验内容来自educoder,通过实验获得更具体的认知
本阶段将学习中断/异常的响应和处理 ,学习系统调用的处理过程。
实验1
通过实际操作回答在输出第一行 0/1 字符的过程中(如下图所示),共发生了几次时钟中断?
跟踪分析时钟中断
等待 gdb 完全启动之后可以在函数 do_timer(由时钟中断的处理函数 timer_interrupt
调用)处设置断点;
让程序继续运行(使用命令 c ),分析在输出第一行 0/1 字符的过程中断点 do_timer
出现的次数,此即为时钟中断的次数。
通过全局变量jiffies
可以直接查看已发生的时钟中断的次数。
中断/异常的恢复点分析
当一个中断/异常被 gdb 捕获时,通常正在运行中断处理程序,这时可以继续跟踪,直至回到恢复点指令。以时钟中断为例,为了从函数 do_timer
跟踪到恢复点,可以如下操作:
由上图可见时钟中断处理程序的入口是 timer_interrupt
函数。
跟踪到当前函数(do_timer)执行完毕返回到 timer_interrupt 函数;
跟踪到 timer_interrupt 函数(用汇编语言写的)末尾的 iret 指令;
si
:Execute one machine instruction, then stop and return to the debugger.
执行该 iret 指令,返回到恢复点;
通过反汇编命令:disas ,分析恢复点指令的地址。
实验2
本关任务:修改版本 1 内核源码,使得每次时钟中断发生时,都在屏幕上输出字符‘t’
时钟中断处理程序
时钟中断处理程序为 timer_interrupt
,每次时钟中断发生时都会执行此函数,此函数用汇编语言编写。
字符输出可以使用指令 int 0x81
,该指令会输出一个字符到屏幕上,字符的 ASCII 码通过 AX 寄存器传递。
例如,为了输出的字符‘0’,可用如下指令:
判断已经发生了多少次时钟中断
已经发生的时钟中断的次数记录在全局变量 jiffies 中,每发生一次时钟中断,该变量的值就增加 1 。
实验3
通过相关知识回答下列问题:
1.在函数 main 的语句jiffies = jiffies/0;所对应的汇编指令片段中,有一个 idiv 指令,此指令的地址是多少?
2.在该 idiv 指令执行之前,当前指令位置(CS:EIP)和栈位置(SS:ESP)分别是多少?
3.使用 si 命令执行了该指令后,新指令位置和栈位置分别是多少?此时栈中保存的恢复点位置和用户栈位置分别是多少?(使用 gdb 调试内核,是为了跟踪到 main 函数入口)
响应中断/异常时,CPU 做了哪些工作
1.切换到核心栈,并在其中保存中断现场。
2. 转到中断处理程序去运行,并切换到核心态。
上图显示了栈中中断现场的结构,(OLD SS:OLD ESP) 描述了用户栈顶的位置,(OLD CS:OLD EIP) 描述了恢复点的位置。
如何查看当前栈顶的状态
可以使用命令 x 来查看:
上面显示了栈顶的 5 个长字,是某异常发生时的中断现场,其中存储的用户栈顶的位置是 0x17:0x2573c ,存储的恢复点的位置是 0xf:0x7967 。需要注意的是,x86 中栈是从高地址向低地址方向增长的,这里的栈顶位置是 0x1fa0c
查看 C 语句编译之后对应的汇编指令片段
如果要查看某条 C 语句编译之后对应的汇编指令片段,可以在该 C 语句处设置断点,并跟踪到该断点,然后反汇编,所看到的当前指令之后的一段汇编指令就对应于该 C 语句。
例如,jiffies = jiffies/0
;是文件 main.c 的第 147 行,可以如下方式查看:
上面显示的汇编指令中,有一行前面有箭头标识,此即为当前指令,即马上将要执行的指令。
实验4
1.在 0 号进程执行 fork 系统调用中的陷入指令(int 0x80)之前,当前指令位置(CS:EIP)和栈位置(SS:ESP)分别是多少?
2.使用 si 命令执行了该指令后,新指令位置和栈位置分别是多少?
3.此时栈中保存的恢复点位置和用户栈位置分别是多少?
跟踪到系统调用的陷入指令(int 0x80)执行之前
一般而言,可以在该系统调用处设置断点,跟踪到该断点,然后使用 si
命令单步执行到陷入指令。但是,对于 main 函数里的 fork 系统调用,不能这样操作(因为 gdb 有时断点设置不够准),可以先跟踪到前一行的 move_to_user_mode 语句,然后使用 n 单步执行,即可到达 fork 系统调用的开始,此时再反汇编disas
,找到陷入指令:
注:
finish
:Continue running until just after function in the selected stack frame returns. Print the returned value (if any). This command can be abbreviated as fin
.
问:版本 1 内核的第 6 次时钟中断发生时,断点和恢复点(指令地址)分别是多少?
断点指令和恢复点指令的分析
对于外部中断而言,恢复点指令是断点指令的后一条。需要说明的是,loop 指令的功能是先将 ecx
寄存器减一,然后检查其值,如果其值非 0 ,则继续循环,否则中止循环,执行下一条指令。以如下指令为例:
其功能是:在地址 0x7977
处循环,每次 ecx 寄存器都减一,直到其值为 0 。因此,loop 指令的上一条有可能是它自己。
知识点网络整理: