汇编语言笔记16直接定址表
汇编语言笔记16直接定址表
0x00 数据标号
上面这个代码中 a b只作为地址标号,标识 两个数据的首地址的偏移地址,编译时作为一个地址常数
上述代码中 a b 作为标号 不仅可以标识对应数据在汇编时的偏移地址,还描述了对应数据的长度,区别于之前没有冒号的标号,称为数据标号
例如 mov ax,b 相当于mov ax,cs:[8]
mov b,2,相当于 mov word ptr cs:[8],2
mov al,a[si] 相当于 mov al,cs:0[si]
mov al,a[3] 相当于 mov al,cs:0[3]
mov al,b会发生错误,因为b标号代表的内存单元是字单元,而al是8位寄存器
add b,ax同样会发生错误,只能 add ax,b
使用这种包含单元长度的标号,可以让我们以简洁的形式访问内存中的数据。称这种标号为数据标号,标记了存储数据的单元地址和长度,不同于仅仅标识地址的地址标号
mov ax,a[si] add b,ax add si,2
在其他段使用数据标号
一般我们不在代码段中定义数据,在其他段中,也可以用数据标号来描述储存数据的单元的地址和长度。而加有冒号:的地址标号,则只能在代码段使用,其他段不能使用
assume cs:code,ds:data
data segment
a db 1,2,3,4,5,6,7
b dw 0
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov cx,8
s: mov al,a[si]
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
注意,如果在代码段中直接用数据标号访问数据,①既需要用伪指令assume 将标号所在的段和一个段寄存器联系起来(比如上面的ds),②又要在代码中给ds赋值上真正的data段地址
①是为了让编译器知道标号的段地址 在cs里 ②是让cs里存放data段的段地址
可以将标号当作数据来定义比如下面,此时 编译器将标号所表达的地址当作数据的值
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
c dw a b
data ends
相当于下面
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
c dw offset a,offset b
data ends
再比如
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
c dd a b
data ends
相当于下面
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
c dw offset a,offset b
data ends
也就是说,如果数据标号或者地址标号被当作数据,如果是dw 定义的,则是偏移地址 ,如果是dd 则是 偏移地址 ,段地址
mov ax,data mov es,ax 如果要使用数据标号,那么要将标号对应的段寄存器设置好,既然在伪指令里assume 把es和data联系起来,那就要设置es
0x01 直接定址表
一个字节对应两个16进制数,要用0-f来表示,然而如何得到十进制数对应的16进制字符串呢?,最简单的办法就是一个一个比较:
但是这样程序就会很麻烦,所以我们需要能够在数值0-15和字符‘0’-‘f’之间找到一种映射关系
,所以我们建立一张表,表中一次储存字符‘0’-f‘,如下
table db '0123456789ABCDEF'
table这个数据标号的偏移即可找到对应字符。这种通过给出的数据作为查表得依据,得到问题得结果得方法,称为直接定址法
程序入口地址的直接定制表
程序有多个子功能,我们就可以通过地址标号和数据标号,来通过计算的方式得出位置:
assume cs:code,ss:stack
stack segment
db 128 dup (0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,128
mov ax,300h
call setscreen
mov ax,4c00h
int 21h
setscreen:jmp short set
table dw sub1,sub2,sub3,sub 4
set: push ax
cmp ah,3
ja sret
mov bl,ah
mov bh,0
add bx,bx;根据ah中的功能号计算在table中的偏移
call word ptr table[bx]
sret: pop bx
ret
sub1: ....
sub2: ....
sub3: ....
sub4: ....