实验16 编写包含多个功能子程序的中断例程
目录
- 题目要求
- 代码
- 错误代码
- 错误代码分析
- 正确代码
- 补充
题目要求
安装一个新的int 7ch中断例程,为显示输出提供如下功能子程序。
(1) 清屏
(2) 设置前景色
(3) 设置背景色
(4) 向下滚动一行
入口参数说明如下:
(1) 用ah寄存器传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向上滚动一行
(2) 对于1、2号功能,用al传送颜色值,(al)∈{ 0,1,2,3,4,5,6,7 }
代码
错误代码:
assume cs:code
code segment
start: mov ax,cs
mov ds,ax
mov si,offset sscreen
mov ax,0
mov es,ax
mov di,200h
mov cx,offset sscreenend – offset sscreen
cld
rep movsb
; 设置7ch号中断的入口地址
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0
mov ax,4c00h
int 21h
sscreen: jmp short s
table dw sub1, sub2, sub3, sub4
s: push bx
cmp ah,3 ; 判断功能号是否大于3
ja sret
mov bl,ah
mov bh,0
add bx,bx ; 根据ah中的功能号计算对应子程序
; 在table表中的偏移
call word ptr table[bx] ; 调用对应的功能子程序
sret: pop bx
iret
; 清屏子程序
sub1: push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
sub1s: mov byte ptr es:[bx],’ ‘
add bx,2
loop sub1s
pop es
pop cx
pop bx
ret
; 设置前景色子程序
sub2: push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub2s: and byte ptr es:[bx],11111000B
or es:[bx],al
add bx,2
loop sub2s
pop es
pop cx
pop bx
ret
; 设置背景色子程序
sub3: push bx
push cx
push es
mov cl,4
shl al,cl
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub3s: and byte ptr es:[bx],10001111B
or es:[bx],al
add bx,2
loop sub3s
pop es
pop cx
pop bx
ret
; 向下滚动一行子程序
sub4: push cx
push si
push di
push es
push ds
mov si,0b800h
mov es,si
mov ds,si
mov si,160
mov di,0
cld
mov cs,24
sub4s: push cx
mov cx,160
rep movsb
pop cx
loop sub4s
mov cx,80
mov si,0
sub4s1: mov byte ptr [160*24+si], ‘ ‘
add si,2
loop sub4s1
pop ds
pop es
pop di
pop si
pop cx
ret
sscreenend: nop
code ends
end start
错误代码分析:
上面的代码会出错,知道错误在哪里吗?怎么改正?
我们的测试程序主要代码为:
mov ax,0 ; 触发7ch号中断的0号清屏子程序
int 7ch
运行测试程序,跳转不到sub1清屏子程序。用debug进行调试安装安装程序:
当运行到call word ptr table[bx]时,此时地址错误。
我们查看安装程序的汇编指令,正确的位置应该为:
那么究竟是什么原因导致了跳转不到正确的位置?
其实原因很简单,就是table标号表示偏移地址。这个是安装程序,在运行安装程序的时候,它的偏移地址为002A。将table移到7ch中断向量表的入口地址处时,它的值还是002A。此时段地址就为0000H,所以执行call word ptr table[bx]就相当于执行了,call word ptr cs:[002AH]。
那么解决的方法是什么呢?
很简单,在进行指令移植的时候在前面指定偏移地址。使用 org 200H语句,这条语句指定了org 200H后面的指令都会被加载到偏移地址为200H的位置(段地址随便,因为org 200H执行的原因,编译器会将table的偏移位置解析正确了)。我们移植org 200H后面的指令到0:200H的位置。
文章最后面查看知识点补充:org指令。
正确代码:
assume cs:code
code segment
start: mov ax,cs
mov ds,ax
mov si,offset sscreen
mov ax,0
mov es,ax
mov di,200h
mov cx,offset sscreenend – offset sscreen
cld
rep movsb
; 设置7ch号中断的入口地址
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0
mov ax,4c00h
int 21h
org 200h ; 正确的做法,指定此时的偏移地址为200H
sscreen: jmp short s
table dw sub1, sub2, sub3, sub4
s: push bx
cmp ah,3 ; 判断功能号是否大于3
ja sret
mov bl,ah
mov bh,0
add bx,bx ; 根据ah中的功能号计算对应子程序
; 在table表中的偏移
call word ptr table[bx] ; 调用对应的功能子程序
sret: pop bx
iret
; 清屏子程序
sub1: push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
sub1s: mov byte ptr es:[bx],’ ‘
add bx,2
loop sub1s
pop es
pop cx
pop bx
ret
; 设置前景色子程序
sub2: push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub2s: and byte ptr es:[bx],11111000B
or es:[bx],al
add bx,2
loop sub2s
pop es
pop cx
pop bx
ret
; 设置背景色子程序
sub3: push bx
push cx
push es
mov cl,4
shl al,cl
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub3s: and byte ptr es:[bx],10001111B
or es:[bx],al
add bx,2
loop sub3s
pop es
pop cx
pop bx
ret
; 向下滚动一行子程序
sub4: push cx
push si
push di
push es
push ds
mov si,0b800h
mov es,si
mov ds,si
mov si,160
mov di,0
cld
mov cs,24
sub4s: push cx
mov cx,160
rep movsb
pop cx
loop sub4s
mov cx,80
mov si,0
sub4s1: mov byte ptr [160*24+si], ‘ ‘
add si,2
loop sub4s1
pop ds
pop es
pop di
pop si
pop cx
ret
sscreenend: nop
code ends
end start
补充
[1] ORG指令
org(origin)指令指定偏移地址。经常使用中断向量表的时候,我们需要指定偏移位置,因为后边的标号是要发生改变的,我们使用org指令就可以产生一个指定的对齐方式。