第三章讲到要访问的内存数据地址是DS+[···],“[···]”里是用常量表示偏移地址(如:[0]),其实“[···]”里面可以用一个带有数据的寄存器来表示偏移地址(如:[BX])。而且“[···]”里面用常量或寄存器是有差别的。
汇编指令中用于自增的指令 inc (例:inc bx <==> bx = bx + 1)
assume cs:code
code segment
mov bx , 1
inc bx
mov ax , 4c00H
int 21H
code ends
end
由图可以CPU执行指令inc bx 后, bx中的数据进行了加1操作
汇编指令中提供了一个用于进行循环的指令loop,而且CPU提供了一个寄存器于指令loop进行配合。这寄存器是CX(存放循环次数)
CPU执行loop指令时进行两个操作:1)(cx = cx - 1) 2)判断CX是否为零,是则向下执行,否则转到标号处执行程序
注:在汇编中,数据不能以字母开头(如 A000H数据在汇编程序中要写成0A000H)
例子:
assume cs:code
code segment
mov ax , 2000H
mov ds , ax
mov bx , 0
mov ax , [bx]
mov cx , 2
s:add ax , ax
loop s
mov ax , 4c00H
int 21H
code ends
end
由图可以看到指令 mov ax , [bx] 就是把(ds+[bx]<==>2000:0000)中的数据读取到寄存器ax中。
由图可以看到寄存器cx 存储着数据(2),然后先执行指令add ax , ax ,到执行指令 loop s时先判断cx 是否为0 , 不为0,转至到标号(感觉程序编译连接形成执行程序通过debug加载到内存中标号就记录着它所在的偏移地址)处执行程序。
在汇编程序中,如果用指令访问一个内存单元,则指令中必须用DS+[···]来表示内存单元,如果再“[···]”里用一个常量表示偏移地址,就要在[···]前面加上显式地给出段地址所在的寄存器(如:mov ax,ds:[0]),如果没有给出段地址所在的寄存器,编译器masm将指令中的“[常量]”解释为“常量”;如果再“[···]”里用一个存有偏移地址的寄存器,则段地址默认在DS。
注:用于显式地指明内存单元的段地址,在汇编中称为段前缀。(如:DS: )
例子:
1)直接用常量表示偏移地址
assume cs:code
code segment
mov ax , 2000H
mov ds , ax
mov ax , [0]
mov ax , 4c00H
int 21H
code ends
end
利用debug加载到内存中:
观察1455:0005 处的指令 可以看到程序编译连接后指令 mov ax , [0] ==>变成了mov ax , 0000
可以看到指令执行后 ax 寄存器存储了0000,而不是我们想要的2000:0000内存单元的数据
2)加了段前缀后的[常量]
assume cs:code
code segment
mov ax , 2000H
mov ds , ax
mov ax , ds:[0]
mov ax , 4c00H
int 21H
code ends
end
利用debug加载到内存中:
观察1455:0005 处的指令 可以看到程序编译连接后指令 mov ax , ds:[0] ==>变成了 mov ax , [0000]
指令执行后可以看到ax读取了2000:0000的以字为长度的数据
3)通过寄存器bx表示偏移地址
assume cs:code
code segment
mov ax , 2000H
mov ds , ax
mov bx , 0
mov ax , [bx]
mov ax , 4c00H
int 21H
code ends
end
观察1455:0008 处的指令 可以看到程序编译连接后指令mov ax , [bx]
指令执行后可以看到ax读取了2000:0000的以字为长度的数据