内中断
思维导图
debug单步执行命令的原理
基本上,CPU在执行完一条指令之后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断的过程。单步中断的中断类型码为1,则它引发的中断过程如下:
- 取得中断码类型1
- 标志寄存器入栈,TF\IF设置为0
- CS、IP入栈
- IP=(14),CS=(14+2)
首先Debug提供了单步中断的中断处理程序,功能为显示所有寄存器中的内容后等待输入命令。然后,在使用t命令执行执行时,Debug将TF设置为1,使得CPU工作于中断方式下,则在CPU执行完这条指令后就引发单步中断,执行单步中断的中断处理程序,所有寄存器中的内容将被显示在屏幕上,并且等待输入命令。
在进入中断处理程序之前,设置TF=0。从而避免CPU在执行中断处理程序的时候发生单步中断。这就是为什么在终端过程中有TF=0这一步。
最后,CPU提供单步中断功能的原因就是,为单步跟踪程序的执行过程,提供实现机制
响应中断的特殊情况
一般情况下,CPU在执行完当前指令后,如果检测到中断信息,就响应中断,引发中断过程。可是,在有些情况下,CPU在执行完当前指令后,即便是发生中断,也不会相响应。对于这些情况,下面列举其中一种情况来进行说明。
在执行完向ss寄存器传送数据的指令后,即便是发生中断,CPU也不会相应。这样做的主要原因是,SS:SP联合指向栈顶,而对它们的设置应该连续完成。如果在设置完ss的指令后,CPU响应中断,引发中断过程,要在栈中压入标志寄存器,cs和ip的值。而ss改变,sp并未改变,ss:sp指向的不是正确的栈顶,将引起出错误。所以CPU在执行完设置ss 的指令后,不响应中断。
所以我们应该利用这个特性,将设置ss和sp的指令连续存放。
实验12
编写0号中断的处理程序,使得在除法溢出发生时,在屏幕中间显示字符串”divide error!”,然后返回到DOS
思路
- 编写能显示divide error!的0号中断处理程序
- 将终端服务程序移动到0000:0200处
- 修改中断向量表中的0号中断的入口地址,使其指向0000:0200
代码
一些注意事项和问题就写到注释里面了,后面忘了的话记得看看
assume cs:code
code segment
start:
;清屏
mov ah,15
int 10h
mov ah,0
int 10h
;将do0送入内存0000:0200处
;ds:si传送的原始位置
mov ax,code
mov ds,ax
mov si,offset do0
;es:di传送的目的位置
mov ax,0000
mov es,ax
mov di,0200h;!!!!0200后面要加h啊!!
;传送的长度
mov cx,offset do0end - offset do0
;传送的方向 正向传送
cld
rep movsb
;将do0的入口地址0000:0200存储在中断向量表0号表项中
mov ax,0000
mov es,ax
mov word ptr es:[0],0200h ;!!!!在没有寄存器显示指示操作的数据大小的时候,一定要用word或者byte显式指明
mov word ptr es:[2],0000h ;另外你只用写往里面存的数就行了,不用按照高低字节改变,他自己会改变的
mov ax,1000
mov bh,1
div bh
mov ax,4c00h
int 21
;可以显示 overflow的中断处理程序 do0
do0:
jmp do0start
db 'divide error!'
do0start:
mov ax,cs
mov ds,ax
mov si,0202h ;设置ds:si指向字符串
mov ax,0B800H
mov es,ax
mov di,12*160+36*2 ;设置es:di指向字符串
;明白为什么这里它不用这个rep的命令了把,因为显存里面的结构是 要显示的字符+颜色背景啥的,但是这个只能是一个一个的加
mov cx,13;设置字符串长度
; cld;设置传输方向
; rep movsb
s:
mov al,[si]
mov es:[di],al
inc si
add di,2;为什么不用rep命令的原因就在这
loop s
mov ax,4c00h
int 21h
do0end:
nop
code ends
end start