汇编语言(王爽第三版)实验16编写包含多个功能子程序的中断例程
(2017-05-03 09:33:56)
标签:
汇编王爽it教育 |
分类: 汇编语言(王爽第三版)实验 |
实验16 编写包含多个功能子程序的中断例程
(1)
清屏。
(2)
设置前景色。
(3)
设置背景色。
(4)
向上滚动一行。
入口参数说明:
(1)
用 ah
寄存器传递功能号:0
表示清屏,1表示设置前景色,2
表示设置背景色,3
表示向上滚动一行;
(2)
对于2、3号功能,用
al
传送颜色值,(al)
∈{0,1,2,3,4,5,6,7}
程序分析:
【1】这个中断例程怎么实现?是在程序中通过入口参数调用实现功能?还是我们按下屏幕上的键就可以设置?(如果这样就基本达到人机交互的要求了)后者由于int 9例程目前系统下,修改不了,故实现麻烦。
【2】还是按照老套路,安装在0:200H内存开始吧。因为程序也不大。
【3】由于这5个子程序作为整体,同时为int 7ch例程的一部分,所以它们都要安装在0:200H。这涉及到了setscreen中的直接定址表中的各个子程序偏移地址的值,是否需要修改它们?
【4】标号代表的是偏移地址,这些标号都是你所期望的吗?
程序实现:
版本一:安装程序如下
assume cs:code
code segment
start:
;----
;中断程序名称:int7ch_setscreen
;功能:设置屏幕属性(1)清屏。(2) 设置前景色。(3) 设置背景色。(4) 向上滚动一行。
;入口参数:
;(1)ah传递功能号:0表示清屏,1表示设置前景色,2 表示设置背景色,3 表示向上滚动一行;
;对于2、3号功能,用 al 传送颜色值,(al) ∈{0,1,2,3,4,5,6,7}
;返回值:无
;----
int7ch_setscreen:
set:
sret:
;----
;子程序名称:cls
;功能:清屏,利用屏幕写满空格。
;入口参数:无
;返回值:无
;----
cls:
clsloop:mov byte ptr
es:[bx], ' '
;----
;子程序名称:frontcolor
;功能:改变屏幕显示字符的前景色
;入口参数:al
;返回值:无
;----
frontcolor: ;保护寄存器变量
;----
;子程序名称:backcolor
;功能:改变屏幕显示字符的背景色
;入口参数:al
;返回值:无
;----
backcolor: ;保护寄存器变量
;----
;子程序名称:roll
;功能:向上滚动一行,依次将n+1行内容复制到n行,最后一行空。
;入口参数:无
;返回值:无
;----
roll:
copy_row:;逐行复制
cls_row:mov byte ptr es:[160*24+si],' '
int7ch_end:
nop
code ends
end
start
assume cs:code
code segment
start:
中断例程的安装程序 ;int 7ch
push cs
pop ds
将ds:si指向源地址(int7c的机器码) mov si, offset int7ch_setscreen ;
mov ax, 0000H
mov es, ax
;mov di, 200H
将es:di指向目的地址(0:204H向量表中) mov di, 204H ;
前2个字用来存储原来的例程的入口地址 ;
mov cx, offset int7ch_end - offset int7ch_setscreen ;设置传输长度
传输方向为正 cld ;
字节传输 rep movsb ;
mov ax, 0000H
mov es, ax
将原来的例程的入口地址保存在0:200H处,共2个字单元。 ;
将向量表中7ch号ip压栈 push es:[7cH*4] ;
弹栈到0:200H处 pop es:[200H] ;
将向量表中7ch号cs压栈 push es:[7cH*4+2] ;
弹栈到0:202H处 pop es:[202H] ;
设置中断向量表,使7ch条目中断向量指向0000:204H ;
cli
mov word ptr es:[7cH*4], 204H
mov word ptr es:[7cH*4+2], 0000H
sti
mov ax, 4c00H
int 21H
;通知编译器从204H开始重新计算标号
org 204H ;----
;中断程序名称:int7ch_setscreen
;功能:设置屏幕属性(1)清屏。(2) 设置前景色。(3) 设置背景色。(4) 向上滚动一行。
;入口参数:
;(1)ah传递功能号:0表示清屏,1表示设置前景色,2 表示设置背景色,3 表示向上滚动一行;
;对于2、3号功能,用 al 传送颜色值,(al) ∈{0,1,2,3,4,5,6,7}
;返回值:无
;----
int7ch_setscreen:
jmp short set
table dw cls, frontcolor, backcolor, roll set:
保护寄存器 ;
push bx
判断传递的是否大于 3 cmp ah,3 ;
如果大于3,退出 ja sret ;
根据功能号调用对应的功能子程序 ;
mov bl,ah
mov bh,0
根据ah中的功能号计算对应子程序的地址在table表中的偏移 add bx,bx ;
call word ptr table[bx] sret:
pop bx
iret ;----
;子程序名称:cls
;功能:清屏,利用屏幕写满空格。
;入口参数:无
;返回值:无
;----
cls:
保护寄存器变量 ;
push bx
push cx
push es
指向显存缓冲区 ;es:bx
mov bx, 0b800h
mov es, bx
mov bx, 0
满屏显示80*25=2000字符 mov cx, 2000 ;
显存缓冲区写满空格 ; clsloop:mov byte ptr es:[bx], ' '
add bx, 2
loop clsloop
恢复寄存器变量 ;
pop es
pop cx
pop bx
ret ;----
;子程序名称:frontcolor
;功能:改变屏幕显示字符的前景色
;入口参数:al
;返回值:无
;----
frontcolor: ;保护寄存器变量
push bx
push cx
push es
指向显存缓冲区 ;es:bx
mov bx, 0b800h
mov es, bx
mov bx,1
mov cx,2000
改变字符前景色 ;
f_color:and byte ptr es:[bx], 11111000b
利用入口参数al值改变前景色 or es:[bx], al ;
add bx, 2
loop f_color
恢复寄存器变量 ;
pop es
pop cx
pop bx
ret ;----
;子程序名称:backcolor
;功能:改变屏幕显示字符的背景色
;入口参数:al
;返回值:无
;----
backcolor: ;保护寄存器变量
push bx
push cx
push es
指向显存缓冲区 ;es:bx
mov bx, 0b800h
mov es, bx
mov bx,1
mov cx,2000
改变字符背景色 ;
b_color:and byte ptr es:[bx], 10001111b
利用入口参数al值改变背景色 or es:[bx], al ;
add bx, 2
loop b_color
恢复寄存器变量 ;
pop es
pop cx
pop bx
ret ;----
;子程序名称:roll
;功能:向上滚动一行,依次将n+1行内容复制到n行,最后一行空。
;入口参数:无
;返回值:无
;----
roll:
寄存器保护 ;
push cx
push si
push di
push es
push ds
设置es:si(目标地址)和ds:si(源地址)都指向显存缓冲区 ;
mov si,0b800h
mov es, si
mov ds, si
指向第n+1行 mov si,160 ;ds:si
指向第n行 mov di,0 ;es:di
设置方向为正 cld ;
共复制24行 mov cx,24 ; copy_row:;逐行复制
注意:保护cx值,下面必须要用到cx push cx ;
mov cx,160
按字节复制 rep movsb ;
pop cx
loop copy_row
最后一行清空,写入空格 ;
mov cx,80
mov si,0 cls_row:mov byte ptr es:[160*24+si],' '
add si,2
loop cls_row
恢复寄存器变量 ;
pop ds
pop es
pop di
pop si
pop cx
ret
int7ch_end: nop
code ends
end start
【1】table是什么?它是个标号,在编译器层面,它就是一个偏移地址。这个偏移地址怎么来的?是在编译时编译器计算出来的。
我们看下,如果没有下面指令,table代表的标号。
;通知编译器从204H开始重新计算标号
将上面语句注释掉,在int7ch_setscreen程序中添加一条语句(在push bx后面)
mov bx,
offset
table
将装载程序(假定为eee.asm)编译并连接后,执行eee.exe,将int 7ch程序装载到指定地方。
测试int例程,测试程序如下(假定是xxx.asm):
assume cs:code
code segment
start:
code ends
end start
将xxx.asm编译并连接后,debug xxx.exe
单步执行它,观察bx值(调用int 7ch),结果如下(在我们的机器上是):
0000:020F
BB4300
说明table的偏移地址是:0043H,原因,在装载程序编译时,已经将table翻译成地址0043H的,那么其他的标号呢?一样,都不对了。
执行命令:d 0:200
-d 0:200
0000:0200
0000:0210
【2】怎么办?
【3】为什么原来的中断安装程序没有发生这个问题呢?一,直接指定入口地址,不存在子程序调用问题;二,其实在原来的程序中也存在这个问题的,标号不是我们所期望的,但是jmp短转移和条件转移指令依靠的是相对位移,对于标号不敏感。忽略了这个问题了。一句话就是缺org指令就完美了。
【4】这个实验,就是考验我们对于table这个标号的理解,还有就是编译过程。重点是table段的偏移地址和对于指向程序入口地址的内存call指令。
【5】使用cli和sti吧,养成了良好的习惯。
【6】其他子程序,按照书中代码编写就行了。要理解table直接定址表的意义。C语言中的指针数组。
【7】这本书最后一个大实验了。后面那个实验估计费劲了。这个写的不好,欢迎指正!谢谢。