第5章 [bx]和loop指令

1.bx

用[0]表示一个内存单元时,0表示单元的偏移地址,段地址默认在ds中,单元的长度(类型)可以由具体指令中的其他操作对象(比如寄存器)中指出
[bx]同样也表示一个内存单元,它的偏移地址在bx中
inc bx的含义是bx中的内容加1,执行后bx = 2

2.loop

正如它的意思循环
loop指令的格式是: loop 标号
CPU执行 loop指令时两步走(这里圆括号代表一个寄存器或内存单元的内容)
1>(cx)=(cx)-1
2>判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行

通常我们用loop指令来实现循环功能,cx中存放循环次数
程序框架如下
mov cx,循环次数
s:
循环执行的程序段
loop s

调试/执行程序时

大于9FFFh的十六进制数据A000H、A001H...FFFFH在书写时以字母开头,但在汇编源程序中,数据不能以字母开头,所以前面要加0,比如0A001H

在程序执行时 loop s 中的标号 s 已经变为了一个地址

我们只想跟踪循环的过程时,可以用DUBUG里命令G来达到目的,一次执行完标号前的内容,g 0012表示执行程序到当前代码段(段地址在cs中)的0012h处
当进入循环后,我们想要循环一次执行完,可以用p命令来达到目的,DEBUG就会自动重复执行循环中指令,直到(cx)=0为止

Debug和汇编编译器masm对指令不同处理

在Debug中,mov ax,[0] 表示将ds:0处的数据送入ax中
但在汇编源程序中,这个指令被编译器当作指令mov ax,0处理
Dubug将它解释为idata是一个内存单元
编译器将[idata]解释为 idata
目前的方法是将偏移地址送入bx寄存器中,用[bx]的方式来访问内存单元
但是这样比较麻烦,还有一种方法是在[ ]的前面显式地给出段地址所在的段寄存器

段前缀

用于显式地指明内存单元的段地址的ds: cs: ss: es:,在汇编语言中成为段前缀

比如访问2000:0单元
mov ax,2000h
mov ds,ax
mov al,ds:[0]

loop和[bx]的联合应用

在实际编程中,经常会遇到用同一种方法处理地址连续的内存单元中的数据问题。我们需要每次循环的时候,按照同一种方法来改变要访问的内存单元的地址
mov al,[bx] 中bx就可以看作一个代表内存单元地址的变量,我们可以通过改变 bx 中的数值,改变访问的内存单元

计算ffff:0~ffff:b单元中的数据和,结果存储在ds中
1.运算和的结果是字节型数据,范围在0-255之间,12个结果相加不会大于65535,dx能放下
2.不能将ffff:0~ffff:b中的数据累加到ds中,在这里面数据是8位的,不能直接加到16位寄存器dx中,也不能累加到dl中,dl会进位丢失
解决方案
用一个16位寄存器做中介,将内存单元中的8位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配并且结果不会超界

点击查看代码
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov bx,0

mov dx,0

mov cs,12
s:
mov al,[bx]
mov ah,0
add dx,ax
inc bx
loop s

mov ax,4c00h
int 21h

code ends
end

一段安全的空间

8086模式中,随意向一段空间写入内容很危险,这段空间可能存放重要的系统数据或代码
dos和其他合法程序一般都不会使用0:200~0:2ff的256字节空间,使用这段空间是安全的,谨慎起见我们还可以debug查看

上一篇:celery 源码阅读1


下一篇:开源web框架django知识总结(十)