直接定址表的相对偏移地址问题
一开始定义的偏移地址如下
table dw f1,f2,f3,f4
程序不能正常运行,debug发现,偏移地址偏移量过大造成的。
原来保存在table中诸如f1之类的偏移地址实际上是在安装程序进行编译时产生的,也就是说该偏移地址相对标号start处偏移的。而程序安装进内存0000:0200h后作为一个独立的中断例程,本应该相对标号setscreen偏移。所以,我们保存的偏移量应该是在f1的基础上减去setscreen的。
此外,程序在内存0000:0200h处安装,所以还要再加上200h的偏移量。所以table中保存的偏移地址应该改为:
table dw f1-offset setscreen+200h,f2-offset setscreen+200h,f3-offset setscreen+200h,f4-offset setscreen+200h
还要注意的是,table作为一个标号,能够表示偏移地址,但在这个案例中table的偏移地址也是相对标号start的。
其他的细节见注释。
assume cs:code
code segment
start:
;安装
mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset setscreen
mov cx,offset int7end - offset setscreen
cld
rep movsb
;设置中断向量表
mov word ptr es:[7*4],200h
mov word ptr es:[7*4+2],0
mov ax,4c00h
int 21h
;--------------------------------
setscreen:
jmp short set
table dw f1-offset setscreen+200h,f2-offset setscreen+200h,f3-offset setscreen+200h,f4-offset setscreen+200h ; 保存的是在编译时产生的偏移量
set:
push bx
cmp ah,3
ja sret
mov bl,ah
mov bh,0
add bx,bx
sub bx,offset setscreen; 使table相对于setscreen偏移,减去多余的偏移量。
call word ptr table[bx+200h] ; table本身也是一个偏移地址
sret:
pop bx
iret
;--------------------------------
f1:
push bx
push es
push cx
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
f1s:
mov byte ptr es:[bx],' '
add bx,2
loop f1s
pop cx
pop es
pop bx
ret
;---------------------------------
f2:
push bx
push es
push cx
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
f2s:
and byte ptr es:[bx],11111000b
or byte ptr es:[bx],al
add bx,2
loop f2s
pop cx
pop es
pop bx
ret
;---------------------------------
f3:
push bx
push es
push cx
push ax
mov bx,0b800h
mov es,bx
mov bx,1
shl al,1
shl al,1
shl al,1
shl al,1
mov cx,2000
f3s:
and byte ptr es:[bx],10001111b
or byte ptr es:[bx],al
add bx,2
loop f3s
pop ax
pop cx
pop es
pop bx
ret
;---------------------------------
f4:
push cx
push bx
push ds
push es
push si
push di
;将es:di指向n行,0~23
mov bx,0b800h
mov es,bx
mov di,0
;将ds:si指向n+1行,1~24
mov ds,bx
mov si,1*160
;24次循环,利用rep movsb复制
cld
mov cx,24
f4s:
push cx
mov cx,160
rep movsb
pop cx
loop f4s
;最后一行空格符填充
mov cx,80
f4ss:
mov byte ptr ds:[si],' '
add si,2
loop f4ss
pop di
pop si
pop es
pop ds
pop bx
pop cx
ret
int7end:nop
code ends
end start