1. 预备知识
-
编写 7ch 中断相关程序的预备知识同编写 0 号中断,见 上文。
-
寄存器 BP 为指针寄存器,和段寄存器 SS 配合使用访问栈中数据。
2. 实验任务
用 7ch 中断例程实现循环指令的功能,并在屏幕中间显示 80 个绿色的感叹号。调用程序如下:
assume cs:code
code segment
start:
mov ax,0b800h
mov es,ax ;段寄存器ES指向显示区域
mov di,160*12 ;变址寄存器DI指向显示区域的中部
mov bx,offset s-offset se ;设置从标号se到标号s的相对偏移
mov cx,80 ;存放循环次数
s:
mov byte ptr es:[di],'!' ;将'!'写入显示缓冲区
mov byte ptr es:[di+1],2h ;字体颜色为绿色
add di,2 ;每次偏移两个字节
int 7ch ;调用7ch中断例程
se:
mov ax,4c00h
int 21h
code ends
end start
2.1 实验分析
根据上文,将完成本实验分为三个步骤:编写中断处理程序,将中断处理程序放入指定内存,设置中断向量表。
2.1.1 编写中断处理程序
引发 int 7ch 中断后,进入中断例程。首先当前的标志寄存器、CS 和 IP 都要入栈。此时,入栈的 CS:IP 为调用程序的地址,即标号 s 的段地址存放在 CS 中、标号 se 的偏移地址存放在 IP 中。
又因为寄存器 BX 存放了标号 se 到标号 s 的相对偏移,所以标号 s 的偏移地址可通过 (bx) 加上标号 se 的偏移地址得到。得到标号 s 的地址后,用它们来设置 CS 和 IP 即可实现到标号 s 的跳转。
由于在中断处理程序中会用到寄存器 BP,为保护现场将其入栈。此时,从栈顶开始往上依次是寄存器 BP 的内容、标号 se 的偏移地址、标号 s 的段地址和标志寄存器。
栈顶的偏移地址放在寄存器 SP 中,从栈顶往上那个第二个数据为标号 se 的偏移地址,所以标号 se 的偏移地址可表示为 (sp)+2,即标号 s 的偏移地址可表示为 ss:((sp)+2)+(bx)。此时,栈中标号 se 的偏移地址变为标号 s 的偏移地址。后续 iret 恢复现场,将 CS:IP 设置为指向标号 s 的地址。
综上,中断处理程序部分的代码为:
lp:
push bp
mov bp,sp
dec cx
jcxz lpret ;如果(CX)等于0,则跳转到lpret,此时(IP)不变,执行标号se处的代码
add [bp+2],bx ;否则,栈中se的偏移地址变为s的偏移地址,(IP)改变,执行标号s处的代码
lpret:
pop bp
iret
2.1.2 将中断处理程序放入指定内存
根据上文的内容,该部分代码为:
mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset lp
mov cx,offset lpend-offset lp
cld
rep movsb
2.1.3 设置中断向量表
在中断向量表中设置第 7ch 号中断向量为代码 lp 的入口地址。
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h ;高地址写入偏移地址
mov word ptr es:[7ch*4+2],0h ;低地址写入段地址
整体代码为:
assume cs:code
code segment
start:
mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset lp
mov cx,offset lpend-offset lp
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0h
mov ax,4c00h
int 21h
lp:
push bp
mov bp,sp
add [bp+2],bx
pop bp
iret
lpend:
nop
code ends
end start
2.2 实验结果
运行上述程序。首先,查看中断向量表的 7ch 号表项表示的内存单元地址为 0000:0200。
中断处理程序的安装结果如下:
最后,运行调用程序,屏幕显示内容如下:
3. 总结
-
为巩固中断的知识,在上文介绍 0 号中断用于解决除法溢出错误的基础上,本文基于 7ch 中断实现循环指令的功能
-
从两文可知,中断和子程序的处理方法类似,且中断不用保护和恢复现场。中断程序安装成功后,在当前 DOS 窗口下永久生效
-
参考:汇编语言/王爽著.——北京:清华大学出版社,2003