assume cs:code,ds:data,ss:stack
data segment
db 'back to main programs!',0
data ends
stack segment
dw 64 dup (0)
stack ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,128
mov ax,0
mov es,ax
mov di,0200h
mov ax,cs
mov ds,ax
mov si,offset do0
mov cx,offset over
sub cx,si
cld
rep movsb ;安装完毕
mov dx,0
mov ax,0200h
mov es:[0],ax
mov es:[2],dx ;中断向量设置完毕
mov dx,1 ;测试中断程序
mov ax,0
mov bx,1
div bx
mov ax,data
mov ds,ax
mov si,0
mov ax,0b800h
mov es,ax
mov di,14*160+32*2
s0:mov cl,[si]
mov ch,0
jcxz ok0
mov ch,42h
mov es:[di],cx
add di,2
inc si
jmp short s0
ok0:mov ax,4c00h
int 21h
do0:jmp short begin
db 'overflow!',0
begin:push ax
push cx
push dx
push ds
push es
push si
push di
pushf
pop ax
or ax,0100h
push ax
popf
mov ax,cs
mov ds,ax
mov si,0202h
mov ax,0b800h
mov es,ax
mov di,12*160+32*2
s:mov cl,[si]
mov ch,0
jcxz ok
mov ch,42h
mov es:[di],cx
add di,2
inc si
jmp short s
nop
ok:mov di,sp ;恢复了其他寄存器,这时候栈顶才是要返回的地址,但是这又破坏了要保护的寄存器。。
add di,14 ;直接根据保护的寄存器数目定位到要找的返回地址
mov si,ss:[di] ;修改之前div处的指令为两个nop,使div引起的中断可以返回到原程序
mov ax,ss:[di+2]
mov es,ax
mov es:[si],9090h
pop di
pop si
pop es
pop ds
pop dx
pop cx
pop ax
iret
;ok:mov ax,4c00h
; int 21h
over:nop
code ends
end start
因为div溢出引起的中断其实不因该返回原来引起中断的程序。直接在中断处理程序就结束。这里为了说明问题对中断处理程序做了改动。主要有如下:
1.中断处理程序里设置了TF标志,即允许单步中断,方便调试。这相当于debug下的T命令,将TF标志设置为1 。因为DIV溢出中断和单步中断属于不同的中断,所以不会引起像在T中断出现的无限循环处理执行中断处理程序第一条指令。
2.发生中断时,将引起中断的指令的cs:ip存入栈中,然后中断处理程序执行完毕,如果中断处理程序不使程序结束,而试图使用iret返回引起中断的指令,则回到引起中断的指令会再次引起中断。这里,我们在中断处理程序内对引起中断的指令进行了修改,改为两个空转指令,这样就可以安全返回原程序了。