汇编学习笔记(13)直接定址表

不加冒号的数据标号

直接定址表顾名思义就是可以通过给定的数据直接找到所需的地址,主要通过数据标号来实现。

到现在为止我们学习的数据标号的写法都是形如

a: db 1,2,3

其实还有一种写法是这样

a db 1,2,3

看上去只是少了个冒号,但是表示的含义可是大不相同。第一种写法a表示内存单元的地址,而第二种写法a不仅表示内存单元的地址,还表示了内存单元的长度。

 1 ;将a中的数据相加,结果存储在b中
 2 assume cs:code
 3 
 4 code segment
 5     
 6     a: db 1,2,3
 7     b: dw 0
 8     
 9 start:  mov si,offset a
10         mov bx,offset b
11         mov cx,3
12 s:
13         mov al,cs:[si]
14         mov ah,0
15         add cs:[bx],ax
16         inc si
17         loop s
18     
19         mov ax,4c00h
20         int 21h
21 code ends
22 end start

 

可以看到,结果已经存储在b中,采用不加冒号的数据标号写法可以使程序更加简洁。

 1 ;将a中的数据相加,结果存储在b中
 2 assume cs:code
 3 
 4 code segment
 5     
 6     a db 1,2,3
 7     b dw 0
 8     
 9 start:  mov si,0
10         mov cx,3
11 s:
12         mov al,a[si]
13         mov ah,0
14         add b,ax
15         inc si
16         loop s
17     
18         mov ax,4c00h
19         int 21h
20 code ends
21 end start

 

因为不加冒号的数据标号还代表了内存单元的长度,所以"mov al,a[si]"就相当于"mov al,cs:[0]si","add b,ax"就相当于"add cs:[3]".

任何事物都有其两面性,世上没有完全完美的东西,不加冒号的写法有一点是需要注意的:当把数据写在数据段时,必须用assume伪指令将数据段与某一个段寄存器联系起来,否则编译的时候会报错。还是刚才例子如果我们这么写

 1 ;将a中的数据相加,结果存储在b中
 2 assume cs:code
 3 
 4 data segment
 5     a db 1,2,3
 6     b dw 0
 7 data ends
 8 
 9 code segment
10     
11 start:  mov si,0
12         mov cx,3
13 s:
14         mov al,a[si]
15         mov ah,0
16         add b,ax
17         inc si
18         loop s
19     
20         mov ax,4c00h
21         int 21h
22 code ends
23 end start

 

没错,can't address with segment register,错误信息已经很明显,定位不到段地址,这是为什么呢?上文已经说过,形如

mov al,a[si]

的指令在编译时是编译成怎样子的指令

mov al,cs:0[si]

我们把数据写在代码段中用的段地址是cs,而现在数据是写在数据段中,编译器在编译时就不知道数据段所对应的段寄存是多少了,所以需要用assume指令进行关联。

 1 ;将a中的数据相加,结果存储在b中
 2 assume cs:code,es:data
 3 
 4 data segment
 5     a db 1,2,3
 6     b dw 0
 7 data ends
 8 
 9 code segment
10     
11 start:  mov ax,data
12         mov es,ax
13         mov si,0
14         mov cx,3
15 s:
16         mov al,a[si]
17         mov ah,0
18         add b,ax
19         inc si
20         loop s
21     
22         mov ax,4c00h
23         int 21h
24 code ends
25 end start

 

直接定址表

我们通过一个例子来学习

 1 ;以十六进制的形式在屏幕上显示给定的字节型数据
 2 
 3 assume cs:code
 4 
 5 code segment
 6 
 7 start:
 8         mov al,'100'
 9         call show
10         
11         mov ax,4c00h
12         int 21h
13 
14 show:
15     jmp short show1
16     table db '0123456789ABCDEF'
17     
18 show1:
19     push es
20     push bx
21     mov ah,al
22     shr ah,1
23     shr ah,1
24     shr ah,1
25     shr ah,1    ;右移4位得到高位地址
26     and al,00001111b
27     
28     mov bl,ah
29     mov bh,0
30     mov ah,table[bx];高4位的值作为偏移地址得到十六进制的值
31     
32     mov bx,0b800h
33     mov es,bx
34     mov es:[160*12+40*2],ah
35     
36     mov bl,al
37     mov bh,0
38     mov al,table[bx]
39     mov es:[160*12+40*2],al
40     
41     pop bx
42     pop es
43     ret
44 
45 code ends
46 end start

 

在这个例子中,我们使用字节型数据的高4位和低4位来查找作为十六进制数据的偏移值,从而可以快速的找到对应的十六进制,这种直接的映射方法就叫做直接定址表。

posted @ 2014-03-02 22:02  huntstack  阅读(296)  评论(0编辑  收藏  举报