前面,我们已经编写过中断0的中断例程了,现在我们讨论可以供应用程序调用的中断例程的编写方法。下面通过两个问题来讨论。
问题一:编写、安装中断7ch的中断例程。
功能:求一word型数措的平方
。
参数:(ax)=要计算的数据。
返回值:dx, ax中存放结果的高16位和低16位。
应用举例:求2*3456^20
assume cs:code code segment start:mov ax,3456 ;(ax)=3456 int 7ch ;调用中断 7ch 的中断例程,结束ax中的数据的平方 add ax,ax adc dx,dx ;dx:ax存放结果,将结果乘以2 mov ax,4c00h int 21h code ends end start
分析一下,我们要做以下3部分工作。
(1)编写实现求平方功能的程序;
(2)安装程序,将其安装在0:200处;
(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 sqrend - 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 , 4c00h int 21h sqr: mul ax iret ; 相当于 pop IP pop CS popf sqrend: nop code ends end start
注意,在中断例程sqr的最后,要使用iret指令。用汇编语法描述,fret指令的功能为
pop IP pop CS popf
CPU执行int 7ch指令进入中断例程之前,标志寄存器、当前的CS和IP被压入栈中,在执行完中断例程后,应该用fret指令恢复int 7ch执行前的标志寄存器和Cs, IP的值,从而接着执行应用程序。 int指令和fret指令的配合使用与call指令和ret指令的配合使用具有相似的思路。
问题二:编写、安装中断7ch的中断例程。
功能:将一个全是字母,以0结尾的字符串,转化为大写
。
参数:dsai指向字符串的首地址。
应用举例:将data段中的字符串转化为大写。
assume cs:code code segment start: mov ax , cs mov ds , ax mov si , offset capital mov ax , 0 mov es , ax mov di , 200h mov cx , offset capitalend - offset capital cld rep movsb mov ax , 0 mov es , ax mov word ptr es:[7ch*4] , 200h mov word ptr es:[7ch*4+2] , 0 int 7ch mov ax , 4c00h ; 如果中断程序中有这段程序这里就可以不加,如果中断程序中是iret,这里就要加上; int 21h ; 不然无法返回dos输入命令,这里和中断程序都加上这段也可以 capital: jmp short change db 'conversation' , 0 change: mov ax , cs mov ds , ax mov si , 202h mov ax , 0b800h mov es , ax mov di , 7c6h ; 具体在显示缓冲区的显示位置偏移 s: mov cl , [si] mov ch , 0 jcxz return and byte ptr [si] , 11011111b mov cl , [si] mov es:[di] , cl mov byte ptr es:[di+1] , 2 inc si add di , 2 jmp short s return: iret ;这里要写上中断返回或者 mov ax , 4c00h int 21h 返回dos,不然执行后程序无法输入,因为执行完中断CS:IP接着向下去执行了; capitalend: nop code ends end start
在中断例程。apital中用到了寄存器si和cx,编写中断例程和编写子程序的时候具有同样的问题,就是要避免寄存器的冲突。应该注意例程中用到的寄存器的值的保存和恢复。