直接定址表是否要先定义后使用?看起来是的。否则出现错误:
此错误为遍历出错,masm在两次扫描代码时得到的某个标记的地址值不同。
因为在定义直接定址表前就使用了它。修改后没问题。
附代码:
assume cs:code
code segment
start:mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset int7ch
mov ax,offset sub1 - offset int7ch
add ax,200h
mov [si+2],ax
mov ax,offset sub2 - offset int7ch
add ax,200h
mov [si+4],ax
mov ax,offset sub3 - offset int7ch
add ax,200h
mov [si+6],ax
mov ax,offset sub4 - offset int7ch
add ax,200h
mov [si+8],ax
mov cx,offset int7ch_e - offset int7ch
cld
rep movsb
mov ax,200h
mov es:[7ch*4],ax
mov ax,0
mov es:[7ch*4+2],ax
mov ax,4c00h
int 21h
int7ch:jmp short begin
dw 0,0,0,0
begin:push bx
push ds
mov bx,cs
mov ds,bx
mov bl,ah
mov bh,0
add bx,bx
call word ptr [bx].202h
pop ds
pop bx
iret
sub1:push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
s1:mov byte ptr es:[bx],' '
add bx,2
loop s1
pop es
pop cx
pop bx
ret
sub2:push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
s2:and byte ptr es:[bx],11111000b
or byte ptr es:[bx],al
add bx,2
loop s2
pop es
pop cx
pop bx
ret
sub3:push bx
push cx
push es
mov cl,4
shl al,cl
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
s3:and byte ptr es:[bx],10001111b
or byte ptr es:[bx],al
add bx,2
loop s3
pop es
pop cx
pop bx
ret
sub4:push bx
push cx
push es
push si
mov bx,0b800h
mov es,bx
mov cx,24
mov bx,0
s44:push cx
mov cx,80
mov si,0
s4:push es:[bx].160[si]
pop es:[bx][si]
add si,2
loop s4
pop cx
add bx,160
loop s44
pop si
pop es
pop cx
pop bx
ret
int7ch_e:nop
code ends
end start
其中修改部分为:
mov ax,offset sub1 - offset int7ch
add ax,200h
mov [si+2],ax
mov ax,offset sub2 - offset int7ch
add ax,200h
mov [si+4],ax
mov ax,offset sub3 - offset int7ch
add ax,200h
mov [si+6],ax
mov ax,offset sub4 - offset int7ch
add ax,200h
mov [si+8],ax
原先想通过直接引用直接定址表对其中的数据进行访问。
mov ax,offset sub1 - offset int7ch add ax,200h mov table[0],ax mov ax,offset sub2 - offset int7ch add ax,200h mov table[1],ax mov ax,offset sub3 - offset int7ch add ax,200h mov table[2],ax mov ax,offset sub4 - offset int7ch add ax,200h mov table[3],ax
还有一个比较严重的问题:此程序为中断处理程序的安装程序,在用MASM进行编译链接的时候,table标记被解释为table在此安装程序内的偏移,为004E
因此,中断处理程序中对table的引用都是004E 。比如
call byte ptr table[bx]
比如要使用7ch中断中的0号程序,则bx=0 .而table[bx]得到的内存单元是(bx)+004e 并不是我们想要的在中断处理程序中的table值加上偏移量bx定位到的存储子程序IP的内存区。因为table值翻译成二进制代码在编译和链接后就完成了,安装程序只是把代码复制到目的区域。安装完成后0:200处代码如下
红色部分,可以看到call指令使用的寻址call table[bx]代码为call [BX+004E] 。而再看看原安装程序内的情况:
紧接着jmp指令的一条指令,其实不是指令,而是我们定义的四个word型数据。刚好它的偏移地址是004e 也是table标记的地址值。
修改方法是使用数据段的寻址
int7ch:jmp short begin dw 0,0,0,0 begin:push bx push ds mov bx,cs mov ds,bx mov bl,ah mov bh,0 add bx,bx call word ptr [bx].202h pop ds pop bx iret
不使用table了,但是仍然是直接定址表的思想,程序的地址放在一个连续的空间存放。
使用直接定址表主要的问题:call指令目标地址的定位问题。
1.首先是转移目的地址的存储。本来是用一个 table dw 0,0,0,0存储,但是table在编译连接后获得的是在安装程序中的地址,在中断处理程序中是无效的。
2.后来根据传送来的子程序号用call指令定位子程序IP。搞清楚子程序IP到底存储在什么位置