1.[bx]表示内存的用法,loop指令的用法
语法格式
loop 标号
通常我们用loop指令来实现循环功能,cx中存放循环次数。
cpu执行指令过程
1.cx=cx-1
2.判断cx的值是否为0
如果cx不等于0,跳转到标号出执行
如果cx=0,执行loop后面的其它指令。
2.综合应用loop和[BX]编程时,对于类型不一致(8位,16位)、数据超出范围等情形的处理(结合5.3节程序5.3和5.5节实例)
在汇编程序中,数据不能以字母开头。例:A000h在汇编程序中要写为:0A000h
从ds中可以得到PSP的段地址SA,PSP的偏移地址为0,则物理地址为SA*16+0,可用段地址和偏移地址表示为:SA+10h:0
遇到loop指令时,可以用p指令执行,debug自动重复执行循环代码,直到(cx)=0,也可以用g命令来达到目的。
类型不一致时,例:ffff:6单元中是一个字节单元,ax是一个16位寄存器,数据长度不一样,如何赋值?
我们说的是“赋值”,就是说,让ax中的数据的值(数据的大小)和ffff:0006单元中的数据的值(数据的大小)相等。8位数据01h和16位数据0001h的数据长度不一样,但它们的值是相等的。那么我们如何赋值,设ffff:0006单元中的数据是xxh,若要ax中的值和ffff:0006单元中的相等,ax中的数据应为00xxh。所以,若实现ffff:0006单元向ax赋值,应该令(ah)=0,(al)=(ffff6h)。
有两个问题:类型的匹配和结界的不超界。具体的说,就是在做加法的时候,我们有两种方法:
1.(dx)=(dx)+内存中的8位数据;
2.(dl)=(dl)+内存中的8位数据。
第一种方法中的问题是两个运算对象的类型不匹配,第二种方法中的问题是结果有可能超界。解决这两个看似矛盾的问题,目前的方法就是得用一个16位寄存器来做中介,将内存单元中的8位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配并且结果不会超界。
assume cs:code code segment mov ax,0ffffh mov ds,ax mov bx,0 ;初始化ds:bx指向ffff:0 mov dx,0 ;初始化累加寄存器dx,(dx)=0 mov cx,12 ;初始化循环计数寄存器cx,(cx)=12 s: mov al,[bx] mov ah,0 add dx,ax ; 间接向dx中加上((ds)*16+(bx))单元的数值 inc bx ; ds:bx指向下一个单元
loop s mov ax,4c00h int 21h code ends end
3.debug工具中t命令、p命令、g命令用法
t命令
单步执行;遇loop会进入循环内部继续单步执行;遇int会进入中断程序内继续单步执行;
p命令
单步执行;遇loop或int会当作整体执行,不进入内部单步执行;
g命令
执行到指定地址;或遇程序结束或int,则终止执行。
4.debug和masm在处理内存单元上的不同及问题处理方式
在debug中编程实现
mov ax,2000 mov ds,ax mov al,[0] mov bl,[1] mov cl,[2] mov dl,[3]
汇编源程序实现
assume cs:code code segment mov ax,2000h mov ds,ax mov al,[0] mov bl,[1] mov cl,[2] mov dl,[3] mov ax,4c00h int 21h code ends end
可以看出,debug和编译器masm对形如“mov ax,[0]”这类指令在解释上的不同,debug和编译器对这些指令中的“[idata]”有不同的解释。debug将它解释为“[idata]”是一个内存单元,“idata”是内存单元的偏移地址;而编译器将“[idata]"解释为“idata”。
那么解决方法是,可将偏移地址送入bx寄存器,用[bx]的方式来访问内存单元。比如我们可以这样访问2000:0单元。
mov ax,2000h mov ds,ax ;段地址2000h送入ds mov bx,0 ;偏移地址0送入bx mov al,[bx] ;ds:bx单元中的数据送入al