int 指令
int 指令的格式为:int n,n为中断类型码。这里由 n 显式的给出了调用哪一个中断处理程序。
CPU 的中断过程仍然是:
(1)取中断类型码n
(2)标志寄存器入栈,IF=0,TF=0
(3)CS、IP入栈
(4)(IP)=(nx4),(CS)=(nx4+2)
比如:当除法溢出时产生的0号中断,会在屏幕上显示“Divide overflow”。我们也可以通过 int 0 指令来让屏幕上显示“Divide overflow”,虽然此时并没有发生除法溢出。
当编写返回到应用程序的中断处理程序时,它与返回到dos系统的中断例程差别在于,它使用了iret指令来返回到应用程序,后者是通过 mov ax 4c00h int 21h来返回的。
iret指令的功能为IP 出栈,CS 出栈,标志寄存器出栈。它常和 int 指令来配合使用 ,就像 call 和 ret 指令一样。
编写程序实现:在屏幕中间显示80个 '!’。要求用 int 指令来代替 loop 指令,其中需要将循环次数和指令转移位移做为参数。将循环次数放在 cx 中,位移放在 bx 中,完整程序如下:
assume cs:code
code segment
start: mov ax,0b800h
mov es,ax
mov di,160*12
mov bx,offset s-offset se ;设置标号s到se的转移位移
mov cx,80 ;循环次数
s: mov byte ptr es:[di],'!'
add di,2
int 7ch
se: nop
mov ax,4c00h
int 21h
code ends
end start
7ch 中断例程如下:
lp: push bp
mov bp,sp
dec cx
jcxz lpend ;判断cx是否为0
add [bp+2],bx ;用转移位移bx更改IP的值
lpend: pop bp
iret
采用 bp 来作为临时寄存器,需要对它进行入栈保存,结束时恢复。当要用 bx 来修改原来的应用程序偏移地址 IP 时,栈中的情况为:sp 指向 bp 的值,sp+2 指向原来的 IP,sp+4 指向原来的 CS,sp+6 指向原来的标志寄存器。原来程序的段地址 CS 和标号 s 的段地址 CS 是相同,故只需要改变原 IP 的值即可,通过 add [bp+2],bx 来改变。
loop 指令是8位短转移指令,用来替代它的 int 指令是16位的近转移指令,这是需要注意的。
DOS和BIOS中断例程
一般来说,一个供程序员调用的中断例程往往包括多个子程序,中断例程内用传递进来的参数来决定执行哪一个子程序。BIOS和DOS中的参数往往采用 ah 来传递。
int 10h 是BIOS提供的中断例程,其中包含多个和屏幕输出相关的子程序。
int 21h 是DOS提供的中断例程。我们一直使用的是 int 21h 中断例程的 4ch 号子程序,功能为程序返回,可以提供返回值作为参数。如下:
mov ah,4ch ;4c作为参数进行程序返回功能
mov al,0 ;0作为返回值
int 21h
也可以像我们经常使用的那样:
mov ax,4c00h
int 21
实验13
(1)编写安装 int 7ch 中断例程,功能为显示一个用0结束的字符串,中断例程安装在 0:200 处。
参数:(dh)=行号,(dl)=列号,(cl)=颜色,ds:si指向字符串首地址。
程序举例如下:
assume cs:code
data segment
db "welcome to masm!",0
data ends
code segment
start: mov dh,10
mov dl,10
mov cl,2
mov ax,data
mov ds,ax
mov si,0
int 7ch
mov ax,4c00h
int 21h
code ends
end start
7ch 中断例程安装如下:
assume cs:code
code segment
mov ax,cs ;中断处理程序安装在0:200处
mov ds,cs
mov si,offset s
mov ax,0
mov es,ax
mov di,200h
mov cx,offset send-offset s
cld
rep movsb
mov ax,0 ;设置中断向量表
mov ds,ax
mov word ptr ds:[7c*4],200h
mov word ptr ds:[7c*4+2],0
mov ax,4c00h
int 21h
s: push si ;中断处理程序的实现
push es
push di
mov ax,0b800h
mov es,ax
mov di,160*dh+2*dl
lp: mov al,[si]
cmp al,0
je ok
mov es:[di],al
mov es:[di+1],cl
add di,2
inc si
jmp short lp
ok: pop di
pop es
pop si
iret
send: nop ;这条指令是不会执行的,因为它没有被传送过去
code ends
end start
(2)略。
(3)下面程序在屏幕的2,4,6,8行显示4句英文诗,补全程序如下:
assume cs:code
code segment
s1: db'Good,better,best,','$'
s2: db'Never let it rest,','$'
s3: db'Till good is better,','$'
s4: db'And better,best.','$'
s: dw offset s1,offset s2,offset s3,offset s4
row: db 2,4,6,8
start: mov ax,cs
mov ds,ax
mov bx,offset s
mov si,offset row
mov cx,4
ok: mov bh,0 ;选择显示缓冲区第0页
mov dh,[si] ;dh中保存行号
mov dl,0 ;dl中保存列号
mov ah,2 ;调用int 10h的2号子程序:置光标
int 10h
mov dx,[bx] ;ds:dx为待显示字符串的首地址,以'$'作为结尾符
mov ah,9 ;调用int 21h的9号子程序:显示字符串
int 21h
add bx,2
inc si
loop ok
mov ax 4c00h ;调用int 21h的4c号子程序:程序返回,返回值为0
int 21h
code ends
end start