直接定址表是否要先定义后使用?看起来是的。否则出现错误:
此错误为遍历出错,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到底存储在什么位置