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,害我找了好久,还请了个高手帮我找,所以大家也不要像我这样范这么低级的错误啊
- 【WIN32汇编教程】(第一课)配置出WIN32汇编的开发环境
- 欢迎加入编程论坛:www.ghostasm.com 我们提供大量工具和学习的资料。VIP3高级群:89366200
- 在学汇编的来加群
- 为什么因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正呢?
- 第6章 实验5 第二题
- 【WIN32汇编教程】(第四课)编写出第一个“hello ghosthouse”程序
- 【WIN32汇编教程】(第三课)了解win32汇编程序的基本结构
- 【WIN32汇编教程】(第二课)Makefile文件的编写和nmake工具的使用
- 欢迎加入编程论坛:www.ghostasm.com 我们提供大量工具和学习的资料。VIP3高级群:89366200
- 欢迎加入编程论坛:www.ghostasm.com 我们提供大量工具和学习的资料。VIP3高级群:89366200