汇编学习笔记(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

 

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

可以看到,结果已经存储在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

 

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

没错,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位来查找作为十六进制数据的偏移值,从而可以快速的找到对应的十六进制,这种直接的映射方法就叫做直接定址表。

你可能感兴趣的:(学习笔记)