1. int指令
n int格式: int n,n为中断类型码。它的功能是引发中断过程。
n CPU 执行int n指令,相当于引发一个 n号中断的中断过程,执行过程如下:
n (1)取中断类型码n;
n (2)标志寄存器入栈,IF = 0,TF = 0;
n (3)CS、IP入栈;
n (4)(IP) = (n*4),(CS) = (n*4+2)。
n 从此处转去执行n号中断的中断处理程序
assume cs:code
code segment
start: mov ax,0b800h
mov es,ax
mov byte ptr es:[12*160+40*2],’!’
int 0
code ends
end start
n 这个程序在 Windows 2000中的 DOS方式下执行时,将在屏幕中间显示一个“!”,然后显示“Divide overflow”后返回到系统中。
n “!”是我们编程显示的,而,“Divide overflow”是哪里来的呢?
我们的程序中又没有做除法,不可能产生除法溢出。
n 程序是没有做除法,但是在结尾使用了int 0指令。
n CPU执行int 0指令时,将引发中断过程,执行 0号中断处理程序,而系统设置的 0号中断处理程序的功能是显示“Divide overflow”,然后返回到系统。
n 可见,int 指令的最终功能和call指令相似,都是调用一段程序。
n 一般情况下,系统将一些具有一定功能的子程序,以中断处理程序的方式提供给应用程序调用。
2.编写供应用程序调用的中断例程
n 示例一 编写、安装中断7ch的中断例程:
n 功能:求一word型数据的平方。
n 参数: (ax)=要计算的数据。
n 返回值:dx、ax中存放结果的高16位和低16位。
n 应用举例:求2*3456^2
assume cs:code
code segment
start: mov ax,3456;(ax)=3456
int 7ch;调用中断7ch的中断例程,计算ax中的数据的平方
add ax,ax;dx:ax存放结果,讲结果乘以2
mov ax,
int 21h
code ends
end start
n 我们要做三部分工作:
n (1)编程实现求平方功能的程序;
n (2)安装程序,我们将其安装在0:200处;
n (3)设置中断向量表,将程序的入口地址保存在7ch表项中,使其成为中断7ch的中断例程。
assume cs:code
code segment
start:mov ax,cs
mov ds,ax
mov si,offset sqr
mov ax,0
mov es,ax
mov di,200h
mov cx,offset sqlend-offset sqr
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h
mov word ptr Es:[7ch*4+2],0
mov ax,
int 21h
sqr:mul ax
iret
sqlend:nop
code ends
end start
n 示例二 编写、安装中断7ch的中断例程:
n 功能:将一个全是字母,以 0结尾的字符串,转化为大写。
n 参数:ds:si指向字符串的首地址。
n 应用举例:
将data段中的字符转化为大写。
n 应用举例:将data段中的字符转化为大写。
assume cs:code
data segment
db 'conversation',0
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
int 7ch
mov ax,
int 21h
code ends
end start
3. 对int、iret和栈的深入理解
n 问题:用7ch中断例程完成 loop指令的功能。
n loop s 的执行需要两个信息,循环次数和到s的位移,所以,7ch中断例程要完成loop指令的功能,也需要这两个信息作为参数。
n 我们用cx存放循环次数,用bx存放位移。
n 应用举例:在屏幕中间显示80个‘!’。
assume cs:code
code segment
start: mov ax,0b800h
mov es,ax
mov di,160*12
mov bx,offset s - offset se;设置从标号se到标号s的转移位移
mov cx,80
s: mov byte ptr es:[di],'!'
add di,2
int 7ch ;如果(cx)≠0,转移到标号s处
se: nop
mov ax,
int 21h
code ends
end start
n 分析:为了模拟loop指令,7ch中断例程应具备下面的功能:
n (1)dec cx
n (2)如果(cx)≠0,转到标号s 处执行,否则向下执行。
n 下面我们分析7ch中断例程如何实现到目的地址的转移:
n (1)转到标号s显然应设(CS)=标号s的段地址,(IP)=标号s的偏移地址;
n (2)那么,中断例程如何得到标号s的段地址和偏移地址呢? 分析
n (3)现在知道,可以从栈中直接和间接地得到标号s的段地址和偏移地址,那么如何用它们设置CS:IP呢? 分析
n int 7ch引发中断过程后,进入 7ch中断例程,在中断过程中,当前的标志寄存器、CS和IP都要压栈,此时压入的CS和IP中的内容,分别是调用程序的段地址(可以认为是标号 s 的段地址)和int 7ch后一条指令的偏移地址(即标号se的偏移地址)。
n 可见,在中断例程中,可以从栈里取得标号s 的段地址和标号 se的偏移地址,而用标号se的偏移地址加上bx中存放的转移位移就可以得到标号s的偏移地址。
n 可以利用iret指令,我们将栈中的se的偏移地址加上 bx 中的转移位移,则栈中的se的偏移地址就变为了s的偏移地址。
n 我们再使用iret指令,用栈中的内容设置CS、IP,从而实现转移到标号s处。
n 7ch中断例程如下:
lp: push bp
mov bp,sp
dec cx
jcxz lpret
add [bp+2],bx
lpret: pop bp
iret
n 因为要访问栈,使用了 bp,在程序开始处将bp 入栈保存,结束时出栈恢复。
n 当要修改栈中se的偏移地址的时候,栈中的情况为;
n 栈顶处是bp 原来的数值,下面是se的偏移地址,再下面是s的段地址,再下面是标志寄存器的值。
n 而此时,bp中为栈顶的偏移地址,所以((ss)*16+(bp)+2)处为se 的偏移地址,将它加上bx 中的转移位移就变为s的偏移地址。最后用iret出栈返回,CS:IP即从标号s处开始执行指令。
n 如果(cx)=0,则不需要修改栈中 se的偏移地址,直接返回即可。
n CPU从标号se处向下执行指令。