中断,可以理解为"从中间断开",再加上主语就是"从程序流中断开",即CPU不再接着预先定义的代码向下执行,转而去处理中断的信息,有内中断和外中断之分。
内中断是由计算机内部产生的中断信息,8086CPU有以下4种内中断信息:
中断向量表就是存放中断处理程序入口地址的列表。程序的地址由CS:IP表示,所以一个入口地址占4个字节,高位存放段地址,低位存放偏移地址。中断码由一个字节表示最大为256个,故中断向量表为1024字节,8086中的内存地址为0000:0000~0000:03FF.
8086CPU执行中断操作过程如下:
1.取得中断码
2.标志寄存器的值入栈,设置TF,IF=0
3.CS,IP入栈
4.中断程序的入口地址,cs=(中断码*4),ip=(中断码*4+2)
用伪代码描述如下:
1.取得中断码N
2.pushf,TF=0,IF=0
3.push cs,push ip
4.(cs)=(N*4),(ip)=(N*4+2)
编写中断程序和子程序相似,不同的地方是用iret代替ret指令返回,iret指令完成的功能是pop ip,pop cs,popf.为什么要加上pop f呢?因为在中断过程中取得中断码后将标志寄存器入栈pushf所以在执行完成中断程序后需要将标志寄存器的值出栈。
下面从头开始编写除法错误时的中断程序,我们想要达到的效果是发生除法错误时在屏幕中间输出"overflow",中断程序放在0000:0020~0000:02FF这段内存空间中。
根据中断的执行过程来看,我们首先要考虑的是如何把中断程序的地址设置在中断向量表中,为此我们编写如下代码
1 mov ax,0000h 2 mov es,ax 3 mov si,0 4 mov word ptr es:[si],200h 5 mov word ptr es:[si+2],0
设置好中断向量表后,接下来要进行的是将中断程序div0复制到0000:0020开始的内存单元中
1 assume cs:code 2 3 code segment 4 5 start: 6 ;将0020:0000写入中断向量表0号中断码的地址 7 mov ax,0000h 8 mov es,ax 9 mov si,0 10 mov word ptr es:[si],200h 11 mov word ptr es:[si+2],0 12 13 ;设置ds:si指向div0 14 mov ax,cs 15 mov ds,ax 16 mov si,offset div0 17 ;设置es:di指向0000:0020 18 mov ax,0 19 mov es,ax 20 mov di,0020h 21 22 ;将div0长度传入cx 23 mov cx,offset div0end-offset div0 24 25 cld ;设置df=0,si,di递增 26 ;传输div0 27 rep movsb 28 29 mov ax,4C00h 30 int 21h 31 32 div0: 33 ... 34 div0end: 35 nop 36 37 code ends 38 end start
前期的准备工作做好后,就可以开始编写中断程序div0了
1 assume cs:code 2 3 code segment 4 5 start: 6 7 ;设置ds:si指向div0 8 mov ax,cs 9 mov ds,ax 10 mov si,offset div0 11 ;设置es:di指向0000:0020 12 mov ax,0 13 mov es,ax 14 mov di,0020h 15 16 ;将div0长度传入cx 17 mov cx,offset div0end-offset div0 18 19 cld ;设置df=0,si,di递增 20 ;传输div0 21 rep movsb 22 23 ;将0020:0000写入中断向量表0号中断码的地址 24 mov ax,0000h 25 mov es,ax 26 mov si,0 27 mov word ptr es:[si],200h 28 mov word ptr es:[si+2],0 29 30 mov ax,4C00h 31 int 21h 32 33 div0: 34 ;'overflow'若放在主程序中,当主程序执行完成后内存单元释放,'overflow'所在 35 ;内存单元有可能会被其他程序占用 36 jmp short div0start 37 db 'overflow' 38 39 div0start: 40 ;ds:si指向'overflow' 41 mov ax,cs 42 mov ds,ax 43 ;jmp short div0start占两个字节 44 mov si,202h 45 46 ;屏幕中间显示 47 mov ax,0b800h 48 mov es,ax 49 mov di,160*12+36*2 50 51 mov cx,9 52 53 s: 54 mov al,ds:[si] 55 mov es:[di],al 56 inc si 57 add di,2 58 loop s 59 60 mov ax,4C00h 61 int 21h 62 63 div0end: 64 nop 65 66 code ends 67 end start
写完编译运行,发现程序卡住不动了,这是什么情况?Debug查看后发现,0000:0020处已有程序占用
会不会是这个原因造成的呢?试试就知道了,继续使用d命令查找空闲内存,发现01e0开始的内存空间都是空闲的,故修改代码如下
1 assume cs:code 2 3 code segment 4 5 start: 6 7 ;设置ds:si指向div0 8 mov ax,cs 9 mov ds,ax 10 mov si,offset div0 11 ;设置es:di指向0000:01e0 12 mov ax,0 13 mov es,ax 14 mov di,01e0h 15 16 ;将div0长度传入cx 17 mov cx,offset div0end-offset div0 18 19 cld ;设置df=0,si,di递增 20 ;传输div0 21 rep movsb 22 ;mov al,ds:[si] 23 ;mov es:[di],al 24 ;inc di 25 ;inc si 26 ;s1: 27 ;movsb 28 ;loop s1 29 30 ;将01e0:0000写入中断向量表0号中断码的地址 31 mov ax,0000h 32 mov es,ax 33 mov si,0 34 mov word ptr es:[si],01e0h 35 mov word ptr es:[si+2],0 36 37 int 0 38 39 mov ax,4C00h 40 int 21h 41 42 div0: 43 ;'overflow'若放在主程序中,当主程序执行完成后内存单元释放,'overflow'所在 44 ;内存单元有可能会被其他程序占用 45 jmp short div0start 46 db 'overflow' 47 48 div0start: 49 ;ds:si指向'overflow' 50 mov ax,cs 51 mov ds,ax 52 ;jmp short div0start占两个字节 53 mov si,01e2h 54 55 ;屏幕中间显示 56 mov ax,0b800h 57 mov es,ax 58 mov di,160*12+36*2 59 60 mov cx,8 61 62 s: 63 mov al,ds:[si] 64 mov es:[di],al 65 inc si 66 add di,2 67 loop s 68 69 mov ax,4C00h 70 int 21h 71 72 div0end: 73 nop 74 75 code ends 76 end start
编译运行,没问题,OK!