描述单元长度的标号

我们可以使用下面的标号来表示数据的开始:

  1. ···
  2. code segment
  3. a:db 1,2,3,4,5,6,7,8
  4. b:dw 0
  5. ···
  6. code ends
  7. ···

a,b都是代表对应数据的起始地址,但并不能判断数据的长度或类型。下面一段程序将a中的8个数累加存入b中:

  1. assume cs:code
  2. code segment
  3. a db 1,2,3,4,5,6,7,8
  4. b dw 0
  5. start mov si,0
  6. mov cx,8
  7. s:mov al,a[si]
  8. mov ah,0
  9. add b,ax
  10. inc si
  11. loop s
  12. mov ax,4c00h
  13. int 21h
  14. code ends
  15. end start

code段中a和b后并没有”:”号,这种写法同时描述内存地址和单元长度的标号。a描述了地址code:0和从这个地址开始后的内存单元都是字节单元,而b描述了地址code:8和从这个地址开始以后的内存单元都是字单元。所以b相当于CS:[8],a[si]相当于CS:0[si],使用这种标号,我们可以间接地访问内存数据。

其它段中使用数据标号

刚说的第一种标号即加”:”号的标号,只能使用在代码段中,不能在其他段中使用。如果想要在其它段中(如data段)使用标号可以使用第二种:

  1. assume cs:code,ds:data
  2. data segment
  3. a db 1,2,3,4,5,6,7,8
  4. b dw 0
  5. data ends
  6. ···
  7. start mov ax,data
  8. mov ds,ax
  9. mov si,0
  10. mov al,a[si]
  11. ···

如果想在代码段中直接使用数据标号访问数据,需要使用assume伪指令将标号所在段和一个寄存器联系起来,是让寄存器明白,我们要访问的数据在ds指向的段中,但编译器并不会真的将段地址存入ds中,我们做了如下假设之后,编译器在编译的时候就会默认ds中已经存放了data的地址,如下面的编译例子:

  1. mov al,a[si]
  2. 编译为:mov al,[si+0]

可以看出编译器默认了a[si]在ds所在的段中。所以我们需要手工指定ds指向data:

  1. mov ax,data
  2. mov ds,ax

也可以这么使用:

  1. data segment
  2. a db 1,2,3,4,5,6,7,8
  3. b dw 0
  4. c a,b
  5. data ends

c处存放的是a和b的偏移地址,相当于c dw offset a,offset b。同理c dd a,b相当于c dw offset a,seg a,offset b,seg b即存的是a和b的段地址和偏移地址。

直接定址表

使用查表的方法编写相关程序,如输出一个字节型数据的16进制形式(子程序):

  1. showbyte jmp short show
  2. table db '0123456789ABCDEF'
  3. show:push bx
  4. push es
  5. mov ah,al
  6. she ah,1
  7. she ah,1
  8. she ah,1
  9. she ah,1 ;右移四位,位移子程序限制使用的寄存器数,只能这么移
  10. and al,00001111b
  11. mov bl,al
  12. mov bh,0
  13. mov ah,table[bx] ;高四位作为相对于table的偏移,取得对应字符
  14. mov bx,0b800h
  15. mov es,bx
  16. mov es:[160*12+40*2],ah
  17. mov bl,al
  18. mov bh,0
  19. mov al,table[bx]
  20. mov es:[160*12+40*2+2],al
  21. pop es
  22. pop bx
  23. ret

可见我们直接使用需要的数值和地址的映射关系来寻找需要的数据。

程序入口地址的直接定址表

可以看书P296的例程,主要思想是,编写多个子程序实现不同功能,每个子程序有自己的标号,如sub1,sub2···等。将它们存在一个表中:

  1. table dw sub1,sub2,sub3,sub4

然后按照之前的方法使用如:

  1. setscreen:jmp short set
  2. table dw sub1,sub2,sub3,sub4
  3. set:push bx
  4. cmp ah,3
  5. ja sret
  6. mov bl,ah
  7. mov bh,0
  8. add bx,bx
  9. call word ptr table[bx]
  10. sret:pop bx
  11. ret