实验16——为了节约内存,拼了。。。
在正式开始做实验16之前,我不知道0:200到0:2ff的空间够不够放得下四个子程序。在看16.4的时候,我发现子程序2和子程序3的功能基本相同,一个是改前景色,一个是改背景色,代码也基本相同。我想,既然不能确定内存空间够不够,干脆就采用最节约的方式吧,把程序2和程序3做成一个程序
当然了,我遇到了大家初次做实验16应该都会遇到的问题,就是假如采用16.4的思路,直接定址表中的内存地址在安装之后是错的。笨人当然有笨人的策略,于是我就这样做了:
assume cs:code
stack segment stack
dw 32 dup(0)
stack ends
code segment
start:mov ax, cs
mov ds, ax
mov si, offset int7ch
xor ax, ax
mov es, ax
mov di, 200h
mov cx, offset int7chend - offset int7ch
cld
rep movsb
cli
mov word ptr es:, 200h
mov word ptr es:, 0h
sti
mov ax, 4c00h
int 21h
int7ch: jmp short screenstart
dw sub1 - int7ch + 200h, sub23 - int7ch + 200h, sub23 - int7ch + 200h, sub4 - int7ch + 200h
screenstart:
push bx
cmp ah, 3
ja quit
mov bl, ah
xor bh, bh
add bx, bx
call word ptr cs:
quit: pop bx
iret
sub1: push cx
push ds
push si
mov si, 0b800h
mov ds, si
mov si, 0
mov cx, 4000h
sub1s:mov byte ptr , 0
add si, 2
loop sub1s
pop si
pop ds
pop cx
ret
; 子程序2和3的功能类似,合并为一了
sub23:push bx
push cx
push ds
push si
jmp sub23switch
submask db 11111000b, 10001111b ; 色彩掩码
bits db 0, 4 ; 移动位数
sub23switch:
mov bx, 0b800h
mov ds, bx
mov si, 1
mov bl, ah
xor bh, bh
shr bx, 1 ; 这里是将1和2对应为0和1
; 假如修改背景色,al是要左移4位的
mov cl, cs:
shl al, cl
mov bl, cs:
mov cx, 2000h
sub23s: and , bl
or , al
add si, 2
loop sub23s
pop si
pop ds
pop cx
pop bx
ret
sub4: push cx
push ds
push es
push si
push di
mov si, 0b800h
mov ds, si
mov es, si
mov si, 80 * 2
mov di, 0
cld
mov cx, 24
sub4s:push cx
mov cx, 160
rep movsb
pop cx
loop sub4s
mov cx, 80
sub4s1: mov byte ptr , 0
add si, 2
loop sub4s1
pop di
pop si
pop es
pop ds
pop cx
ret
int7chend:
nop
code ends
end start
大约可以节省15字节的空间
定址方法并不算好,只是权宜之计。假如中断程序安装的位置发生了变化,本程序需要修改的地方还是比较多的。
下面总结两种个人认为很有价值的方案:
1、将需要安装的中断程序放在主程序前面。这样的好处在于不论在安装程序中还是在安装后的中断程序中,直接定址表中保存的偏移地址是一致的,不需要像我的程序需要大量换算。此时,中断向量表中的cs和ip就不能是0和200h了,而应该是20h和0,个中妙处实在难以言喻。
2、采用ORG伪指令。依旧是主程序在前中断程序在后,但在中断程序前加ORG 200h指令,规定下面的代码从200h开始,这样一来,直接定址表就会按照200h为基准计算偏移。
以上两种方案的优势均在于思路直观,便于修改
ps:如果采用宏,我的程序也并不是很难改的,只是我还不会 :P
页:
[1]