第五章
预备知识
[bx]同样表示一个内存单元,偏移地址在bx中,段地址在ds中
我们用描述性的符号()来表示一个寄存器或一个内存单元中的内容
(ax)表示ax中的内容,(20000H)表示内存20000H单元的内容
((ds)*16+(bx)),ds中的内容为ADR1,bx中的内容为ADR2,所以表示ADR1:ADR2单元的内容
(2000:0)、((ds):1000H)是不正确的用法
一些具体应用
mov ax,[2]可以描述为(ax)=((ds)*16+2)
push ax可以描述为 (sp)=(sp)-2 ((ss)*16+(sp))=(ax)
(X)所表示的数据有两种类型:字节或者字,是哪种类型由寄存器名或具体的运算决定
(al) (bl)为字节型 (ds) (ax)为字型
5.1 [BX]
inc bx ;bx自增
mov [bx],ax ;传入一个字,[bx]后一个单元也被赋值
mov [bx],al ;传入一个字节
5.2 Loop指令
CPU执行loop指令的时候,先(cx)=(cx)-1,再判断cx中的值,不为零则转至标号处执行程序,为零则向下执行,所以cx中存放着循环次数、
实例:计算2^12
assume cs:code
code segment
mov ax,2
mov cx,11
s:add ax,ax
loop s
mov ax,4c00H
int 21H
code ends
end
循环框架如下
mov cx,循环次数
s:
循环执行的程序段
loop s
实现用加法计算123*236,一种是123加236次,另一种是235加123次,显然后者更快
assume cs:code
code segment
mov ax,0
mov cx,123
s:add ax,236
loop s
mov ax,4c00H
int 21H
code ends
end
5.3 在Debug中跟踪用loop指令实现的循环程序
考虑一个问题,计算ffff:0006单元中的数乘以3.结果存储在dx中
1、运算的结果是否会超出dx所能存储的范围?
255*3 < 65535 不会
2、将ffff:0006单元中的数值赋给ax,用dx做3次(dx)=(dx)+(ax),但ffff:6是一个字节单元,ax是16位的寄存器,长度不一样,如何赋值?
如果mov ax,[6] 赋值时ffff:0006中的内容会传到ax的低位,而ffff:0007中的内容会传到ax的高位,为了使ax中数值大小上=与ffff:0006单元上的数值大小相同,我们设法使ah=0
assume cs:code
code segment
mov ax,0ffffH
mov ds,ax
mov bx,6 ;ds:bx
mov al,[bx]
mov ah,0 ;使得大小上相等
mov dx,0
mov cx,3
s:add dx,ax
loop s
mov ax,4c00H
int 21H
code ends
end
注意第一条指令,在汇编源程序中,数据不能以字母开头,所以要在前面加0,A000H在汇编源程序中写为0A000H
在Debug中,loop s会变为loop s所指的地址,如loop 0012
假设循环程序段从CS:0012开始,之前的代码不想一步步执行,可以使用g 0012,Debug从当前CS:IP指向的指令开始,一直到(IP)=0012H
如果循环次数过多,可以在再次遇到loop指令时使用p命令,自动执行剩下的循环,直到cx为0,也可以用g 1006(假设CS:1006为loop指令下一条指令的地址)
5.4 Debug和masm对指令的不同处理
在Debug写指令mov ax,[0],表示将ds:0处的数据送入ax,但在汇编源程序中,指令mov ax,[0]被编译器当作指令mov ax,0处理,因此,如果要将2000:0单元中的数据送入al,用[bx]的方式来访问内存单元
mov ax,2000H
mov ds,ax
mov bx,0
mov al,[bx]
但这样十分麻烦,因此我们采取显示地给出段地址所在的段寄存器的方法
mov ax,2000H
mov ds,ax
mov al,ds:[0]
总结:[…]中为常量idata,前面需要显示地给出段寄存器,否则masm将[idata]解释为idata,如果[…]中为寄存器,则段地址默认在ds中,当然也可以显示得给出段地址所在的段寄存器
5.5 loop和[bx]的联合应用
计算ffff:0~ffff:b单元中数据的和,结果存储在dx中
运算结果不会超出dx的存储范围,但是不能将ffff:0~ffff:b中的数据直接累加到dx中,因为前者的数据是8位的,长度不匹配,但如果累加到dl中,(dh)=0,很可能造成进位损失,所以用一个16位寄存器来做中介
assume cs:code
code segment
mov ax,0ffffH
mov ds,ax
mov bx,0
mov dx,0
mov cx,12 ;0~b 一共12次
s:mov al,[bx]
mov ah,0
add dx,ax
inc bx
loop s
mov ax,4c00H
int 21H
code ends
end
5.6 段前缀
mov ax,ds:[bx]
mov ax,cs:[bx]
mov ax,ss:[bx]
mov ax,es:[bx]
mov ax,ss:[0]
mov ax,cs:[0]
ds: cs: ss: es: 在汇编语言中称为段前缀
5.7 一段安全的空间
在8086模式中,随意向一段内存空间写入内存是很危险的,可能这段内存中有重要的数据或代码
如果我们需要向内存空间写入数据的话,要使用操作系统给我们分配的空间
DOS方式下,一般0:200~0:2ff空间中没有系统或其他程序的数据或代码,在需要向内存中写入数据时,就使用这段空间
5.8 段前缀的使用
将内存ffff:0·ffff:b单元中的数据复制到0:200~0:20b单元中
assume cs:code
code segment
mov ax,0ffffH
mov ds,ax
mov ax,0020H
mov es,ax
mov bx,0
mov cx,12
s:mov dl,[bx]
mov es:[bx],dl
inc bx
loop s
mov ax,4c00H
int 21H
code ends
end