汇编网首页登录博客注册
mahdi_glt的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
最新评论
最新留言
文章收藏
友情链接

[2011-05-16 23:23] 实验16 使用数据标号编写中断例程

assume cs:code

code segment
;==================中断例程======================
;这段程序将被写入内存
;这里table后面sub的标号在编译的时候会被转换成标号对应的内存偏移地址
;这里的call指令的位移地址等于sub标签处的地址减去call后一条指令的IP地址
;是的程序能够正确的调用子程序,但是安装了之后,call的位置发生变化了,
;由于sub标签的地址仍是以前的那个,导致计算出来的位移不准确,会跳转到
;其他的地方去,为了避免跳转不准备,我们把中断例程都放在程序的开头处
;即第一条指令都在偏移地址0处,这样计算的位移就可以相等了
setscreen:
                jmp screen_start
                table dw sub1,sub2,sub3,sub4;例程中定义的数据
                ;判断ch是否超过3,调用子程序
screen_start:
                push bx
                cmp ah,3
                ja screen_ok ;判断ah的值是否超过3,若果超过了则返回主程序
                mov bh,0
                mov bl,ah        ;用bx保存传入选项的值
                add bx,bx        ;计算出定址表中的位置
                call word ptr cs:table[bx] ;从定址表中找出子程序的地址
screen_ok:
                pop bx
                iret
                
;---------------子程序 清屏---------------
sub1:        
                push bx
                push cx
                push es
                mov bx,0b800h
                mov es,bx
                mov cx,2000
                mov bx,0
        ss1:mov byte ptr es:[bx],' '
                add bx,2
                loop ss1
                pop es
                pop cx
                pop bx
                ret
                
;---------------子程序 设置前景色----------------
sub2:        
                push ax
                push bx
                push cx
                push es
                mov bx,0b800h
                mov es,bx
                mov cx,2000
                mov bx,1
                and al,11110111b        ;将第3位清0,避免是高亮发生变化
        ss2:and byte ptr es:[bx],11111000b
                or byte ptr es:[bx],al
                add bx,2
                loop ss2
                pop es
                pop cx
                pop bx
                pop ax
                ret
        
;----------------子程序 设置背景色---------------
sub3:
                push ax
                push bx
                push cx
                push es
                mov bx,0b800h
                mov es,bx
                and al,11110111b;将第3位清0,为了防止第3位被改动而改变高亮位
                mov cl,4
                shl al,cl
                mov cx,2000
                mov bx,1
        ss3:and byte ptr es:[bx],10001111b
                or byte ptr es:[bx],al
                add bx,2
                loop ss3
                pop es
                pop cx
                pop bx
                pop ax
                ret
                
;-----------------子程序 向上滚动1行-------------
sub4:
                push ax
                push bx
                push cx
                push es
                push ds
                push si
                push di
                
                mov bx,0b800h
                mov es,bx
                mov ds,bx
                mov di,0
                mov si,160
                cld
                mov cx,160*25
                rep movsb
                ;将最后一行请除
                mov  cx,80
                mov si,0
        ss4:mov byte ptr es:[24*160+si],' '
                add si,2
                loop ss4
                pop di
                pop si 
                pop ds
                pop es
                pop cx
                pop bx
                pop ax
                ret
setscreen_end:nop
;==================安装例程======================
setting:
                ;保存需要用到寄存器中的数据
                push ax
                push cx
                push ds
                push es
                push si
                push di
                
                push cs
                pop ds        ;ds指向原数据段
                mov ax,20h
                mov es,ax;es指向目标段
                mov si,offset setscreen;原数据偏移地址
                mov di,0        ;目标偏移地址
                mov cx,offset setscreen_end-offset setscreen ;计算出数据长度
                cld ;di,si每次执行movsb的时候都递增1
                rep movsb
                
                ;设置中断向量
                mov ax,0
                mov es,ax        ;es设置为0
                mov word ptr es:[7ch*4],0
                mov word ptr es:[7ch*4+2],20h ;设置中断向量指向20:0处
                
                ;将保存在栈中的数据再压入寄存器中
                pop di
                pop si
                pop es
                pop ds
                pop cx
                pop ax
                ret
;==================主程序入口====================
start:
                call setting;安装中断例程,并设置中断向量
                call text;向屏幕输入字符'X'
                ;设置前景色为红色
                call delay
                mov ah,1
                mov al,4
                int 7ch
                call delay
                ;设置背景色为白色
                mov ah,2
                mov al,7
                int 7ch
                call delay
                ;向上移动两行
                mov cx,2
                mov ah,3
         s1:int 7ch
                call delay
                loop s1
                ;清屏
                mov ah,0
                int 7ch
                call delay
                
                mov ax,4c00h
                int 21h
                        
;------------------延时子程序--------------------
delay:
                push bx
                push dx
                
                mov dx,2000h
                mov bx,0
        dy1:sub bx,1
                sbb dx,0
                cmp bx,0
                jne dy1
                cmp dx,0
                jne dy1
                
                pop dx
                pop bx
                ret
;---------------测试子程序-----------------------
;使这个屏幕都是’X‘
text:        
                push bx
                push cx
                push es
                mov cx,2000
                mov bx,0b800h
                mov es,bx
                mov bx,0
        ts1:mov byte ptr es:[bx],'X'
                add bx,2
                loop ts1
                pop es
                pop cx
                pop bx
                ret
                
code ends
end start

;在这个程序中,我感觉难点在中断例程所放置的位置,因为在安装的过程中会把主程序中SUB标签的地址传过去,而非是在安装完后计算出SUB标签的地址的。所以必须使中断例程的第一条指令与安装好的第一条指令的偏移地址相等,这样计算出的位移量才能正确,调用子程序的时候才能找到正确的地址。
我在写这个程序的时候把POP都写成了PUSH,害我找了好久,还请了个高手帮我找,所以大家也不要像我这样范这么低级的错误啊
评论次数(0)  |  浏览次数(545)  |  类型(我的代码) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码