描述单元长度的标号
之前,我们一直在代码段中使用标号来标记指令,数据,段的起始地址,比如:
assume cs:code
code segment
a:db 1,2,3,4,5,6,7,8
b:dw 0
start: mov si,offset a
mov bx,offset b
程序中,code,a,b,start都是标号,这些标号仅仅表示了内存单元的地址
但是,我们还可以使用一种标号,这种标号不但表示内存单元的地址,还表示了内存单元的长度,即表示了在此标号处的单元,是一个字节单元,还是字单元,还是双字单元
assume cs:code
code segment
a db 1,2,3,4,5,6,7,8
b dw 0
start: mov si,0
mov cx,8
在code段中使用的标号a,b后面没有":",它们是同时描述内存单元和单元长度的标号,标号啊,描述了地址code:0,和从这个地址开始,以后的内存单元都是字节单元,而标号b描述了地址code:8,和从这个地址开始,以后的内存单元都是字单元
因为这种标号包含了对单元长度的描述,所以在指令中,它可以代表一个段中的内存单元,比如,对于程序中的"b dw 0"
指令:mov ax,b
相当于:mov ax,cs:[8]
指令: mov b,2
相当于:mov word ptr cs:[8],2
在其他段中使用数据标号
一般来说,我们不在代码段定义数据,而是将数据定义到其他段,在其他段中,我们也可以使用数据标号来描述存储数据的单元的地址和长度
注意,在后面加有":"的地址标号,只能在代码段中使用,不能在其他段中使用
注意,如果想在代码段中直接用数据标号访问数据,则需要用伪代码assume将标号所在的段和一个段寄存器联系起来,否则编译器在编译时,无法确定标号的段地址在哪个寄存器中,当然这种联系是编译器需要的,但绝不是说,用assume指令将段寄存器和某个段相联系,段寄存器就会真的存放该段的地址,我们在程序中还要使用指令对段寄存器进行设置。
直接定址表
编写子程序,以十六进制的形式在屏幕中间显示给定的字节型数据
分析:一个字节需要用两个十六进制数码来表示,所以,子程序需要在屏幕上显示两个ASCII字符
我们将一个字节的高4位和低4位分开,分别用它们的值得到对应的数码字符,比如2Bh,可以得到高4位的值为2,低4位的值为11,那么如何用这两个数值得到对应的数码字符"2"和"B"
最简单的方法就是一个一个比较:
如果数值为0,则显示"0"
…
如果数值为11,则显示"B"
…
这种方法使用多条比较,转移指令,程序将比较长,混乱
我们希望能够在数值0-15和字符"0"-“F"之间找到一种映射关系
数值0-9和字符"0”-“9"之间的映射关系是很明显的,即:
数值+30h=对应字符的ASCII值
这种方法由于映射方式的不同,我们在程序中必须进行一些比较,对于大于9的数值,我们要用不同的计算方法
具体的做法是,建立一张表,表中依次存储字符"0”-“F”,我们可以通过数值0-15直接查找到对应的字符
子程序如下:
showbyte jmp short show
table db '0123456789ABCDEF'
show: push bx
push es
mov ah,al
shr ah,1
shr ah,1
shr ah,1
shr ah,1//右移4位,ah中得到高4位的值
and al,00001111b//al中为低4位的值
mov bl,ah
mov bh,0
mov ah,table[bx]//用高4位的值作为相对于table的偏移,取得对应的字符
mov bx,0b800h
mov es,bx
mov es:[160*12+40*2],ah
mov bl,al
mov bh,0
mov al.table[bx]//用低四位的值作为相对于table的偏移,取得对应的字符
mov es:[160*12+40*2+2],al
pop es
pop bx
ret
利用表,在两个数据集合之间建立一种映射关系,使我们可以查看表的方法根据给出的数据得到其在另一个集合中的对应数据,这样做的目的一般来说有以下3个:
- 为了算法的清晰和简洁
- 为了加快运算速度
- 为了使程序易于填充