汇编语言(王爽)-内中断


任何一个通用CPU,都可以在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或内部产生的一种特殊信息,并且可以立即对所接收的信息进行处理。这种特殊的信息,称为中断信息

中断在于:CPU不再接着(刚执行完的指令)向下执行,而是转去处理这个特殊信息

中断信息可以来自CPU的内部和外部


内中断的产生

CPU内部产生下面的情况时,将产生相应的中断信息

  1. 除法错误,例:除法溢出

  2. 单步执行

  3. 执行into指令

  4. 执行int指令

8086CPU用称为中断类型码的数据来标识中断信息的来源

中断类型码为一个字节型的数据,可表示256种中断信息的来源

以上4种中断源,在8086CPU中的中断类型码为:

  1. 除法错误:0

  2. 单步执行:1

  3. 执行into指令:4

  4. 执行int指令:该指令格式为int n,指令中的n为字节型立即数,是提供给CPU的中断类型码


中断处理程序

用来处理中断信息的程序被称为中断处理程序

CPU在收到中断信息后,如何根据中断信息确定其处理程序的入口

中断类型码的作用就是用来定位中断处理程序的。如何根据8位中断类型码得到中断处理程序的段地址和偏移地址呢?


中断向量表

CPU用8位的中断类型码通过中断向量表找到相应的中断处理程序的入口地址

中断向量,即中断处理程序的入口地址

中断向量表,即中断处理程序入口地址的列表

中断向量表在内存中保存,其中存放着256个中断源所对应的中断处理程序的入口

1.png

对于8086CPU,中断向量表指定存放在内存地址0处,0000:00000000:03FF的1024个单元中

中断向量表中,一个表项存放一个中断向量,也就是一个中断处理程序的入口地址,一个表项占两个字,高地址字存放段地址,低地址字存放偏移地址

可见,CPU通过中断类型码,查找中断向量表,就可以得到中断程序的入口地址


中断过程

通过中断类型码到中断向量表中找到中断向量,并用它设置CSIP,这个工作由CPU的硬件自动完成,称为中断过程

中断过程:

  1. 从中断信息中取得中断类型码N

  2. 标志寄存器的值入栈pushf

  3. 设置标志寄存器的第8位TF和第9位IF的值为0TF=0,IF=0

  4. CS的内容入栈push CS

  5. IP的内容入栈push IP

  6. 从内存地址为中断类型码*4和中断类型码*4+2的两个字单元中读取中断处理程序的入口地址设置IPCS (IP)=(N*4),(CS)=(N*4+2)

CPU收到中断信息,首先引发中断过程,硬件在完成中断过程后,CS:IP将指向中断处理程序的入口,CPU开始执行中断处理程序


中断处理程序和iret指令

中断处理程序

由于CPU随时都可能检测到中断信息,即CPU随时都可能执行中断处理程序,所以中断处理程序必须一直存储在内存某段空间之中。而中断处理程序的入口地址,即中断向量,必须存储在对应的中断向量表表项中

中断处理程序的编写方法:

  1. 保存用到的寄存器

  2. 处理中断

  3. 恢复用到的寄存器

  4. iret指令返回

iret指令

iret指令描述为:

1
2
3
pop IP
pop CS
popf

iret通常和硬件自动处理的中断过程配合使用

中断过程中,寄存器入栈的顺序为标志寄存器、CSIPiret指令的出栈顺序为IPCS、标志寄存器,实现了执行中断处理程序前中断过程进行保存现场的工作,iret指令执行后,恢复现场的工作


除法错误中断的处理

0号中断,除法错误中断的处理

CPU执行div等除法指令的时候,若发生除法溢出错误,将产生中断类型码为0的中断信息,CPU将检测到这个信息,然后引发中断过程,转去执行0号中断所对应的中断处理程序

1
2
3
mov ax,1000h
mov bh,1
div bh

1.png

0号中断处理程序的功能:显示提示信息Divide overflow后,返回到操作系统中


编程处理0号中断

重新编写0号中断处理程序,功能时在屏幕中间显示overflow!,然后返回到操作系统

分析:

  1. CPU进行中断过程

  2. 编写中断处理程序do0

    1. 相关处理

    2. 向显示缓存区送字符串overflow!

    3. 返回DOS

  3. do0在内存中的存放位置

    内存0000:00000000:03FF,大小为1KB的空间存放中断向量表,8086CPU支持256个中断,但实际上,系统中要处理的中断事件未达到256个,所以在中断向量表中,许多单元是空的

    一般情况下,从0000:02000000:02FF的256个字节空间所对应的中断向量表项为空

    可以将do0传送到内存0000:0200

  4. do0的入口地址,即0000:0200登记在中断向量表的对应表项中。

    0号中断的段地址存放在0*4+2字单元中,偏移地址存放在0*4字单元中

    do0的段地址0存放在0000:0002字单元中,将偏移地址200h存放在0000:0000字单元中

程序框架如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
assume cs:code
code segment

start: do0安装程序
设置中断向量表
mov ax,4c00h
int 21h

do0: 显示字符串"overflow!"
mov ax,4c00h
int 21h

code ends
end start

程序执行时,首先执行do0安装程序,将do0的代码复制到内存0:200处;然后设置中断向量表,将do0的入口地址,即偏移地址200H和段地址0,保存在0号表项中。完成后,程序返回。do0的代码虽然在程序中,但不在程序执行时执行,它是在除法溢出发生的时候才得以执行的中断处理程序


安装程序

使用movsb指令,将do0的代码送入0:200

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
assume cs:code
code segment
start: mov ax,cs
mov ds,ax
mov si,offset do0 ;ds:si指向源地址
mov ax,0
mov es,ax
mov di 200h ;es:di指向目的地址

mov cx,offset do0end-offset do0 ;cx为传输长度

cld ;正向传送
rep movsb

设置中断向量表

mov ax,4c00h
int 21h

do0: 显示字符串"overflow!"
mov ax,4c00h
int 21h

do0end: nop

code ends
end start

-是编译器识别的运算符号,编译器可以用它来进行两个常数的减法

汇编编译器可以处理表达式

例:指令mov ax,(5+3)*5/10,被编译器处理为指令mov ax,4


do0

do0程序主要任务是显示字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
assume cs:code
code segment
start: mov ax,cs
mov ds,ax
mov si,offset do0 ;ds:si指向源地址
mov ax,0
mov es,ax
mov di 200h ;es:di指向目的地址

mov cx,offset do0end-offset do0 ;cx为传输长度

cld ;正向传送
rep movsb

设置中断向量表

mov ax,4c00h
int 21h

do0: jmp short do0start ;用于跳过字符串内存空间,转到正式程序执行
db "overflow!" ;将字符串放到do0中,防止在执行中断处理程序时无法获取字符串

do0start:mov ax,cs
mov ds,ax
mov si,202h ;ds:si指向"overflow!",jmp指令占2个字节

mov ax,0b800h
mov es,ax
mov di,12*160+36*2 ;es:di指向显存空间的中间位置

mov cx,9 ;cx为字符串的长度
s: mov al,[si]
mov es:[di],al
inc si
add di,2 ;显存空间中,第一个字节存放数据,第二个字节存放属性
loop s

mov ax,4c00h
int 21h

do0end: nop

code ends
end start

设置中断向量

do0的入口地址0:200,写入中断向量表的0号表项中,使do0成为0号中断的中断处理程序

0号表项的地址为0:00:0字单元存放偏移地址,0:2字单元存放段地址

1
2
3
4
mov ax,0
mov es,ax
mov word ptr es:[0*4],200h
mov word ptr es:[0*4+2],0

单步中断

基本上,CPU在执行完一条指令之后,若检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程

中断类型码为1,单步中断

中断过程如下:

  1. 取得中断类型码1

  2. 标志寄存器入栈,TFIF设置为0

  3. CSIP入栈

  4. (IP)=(1*4)(CS)=(1*4+2)

Debug提供了单步中断的中断处理程序,功能为显示所有寄存器中的内容后等待输入命令。然后,在使用t命令执行指令时,DebugTF设置为1,使CPU工作于单步中断方式下,则在CPU执行完这条指令后就引发单步中断,执行单步中断的中断处理程序,所有寄存器的内容被显示在屏幕上,并且等待输入命令

若在执行单步处理程序之前,TF=1,则CPU在执行完中断处理程序的第一条指令后,又要产生单步中断,则又要转去执行单步中断的中断处理程序,在执行完中断处理程序的第一条指令后,又要产生单步中断,则又要转去执行单步中断的中断处理程序。。。陷入无限循环

避免无限循环的方法是,在进入中断处理程序之前,设置TF=0,从而避免CPU在执行中断处理程序的时候发生单步中断


响应中断的特殊情况

一般情况下,CPU在执行完当前指令后,若检测到中断信息,就响应中断,引发中断过程

在某些情况下,CPU在执行完当前指令后,即便是发生中断,也不会响应

当执行完向ss寄存器传送数据的指令后,即便发生中断,CPU也不会响应。因ss:sp联合指向栈顶,若响应中断,ss改变,sp未改变,则ss:sp未指向正确的栈顶,将引发错误。所以应利用此特性,将设置sssp的指令连续存放

所以,当使用Debug进行单步执行时,设置好ss寄存器后,CPU未响应单步中断,继续执行设置sp寄存器的指令,之后响应下一次单步中断。单步执行显示结果中未体现设置sp指令的过程,但此指令已经被执行了


---------------The End---------------
0%