[BX]和loop指令
[bx]和[0]有些类似,[0]表示内存单元,它的偏移地址是0。要完整的描述一个内存单元,需要两种信息:1、内存单元的地址;2、内存单元的长度(类型);
用[0]表示一个内存单元时,0表示单元的偏移地址,段地址默认在DS中,单元的长度(类型)可以由具体指令中的其他操作对象(如寄存器——寄存器的位宽)指出。
[BX]同样也是表示一个内存单元,它的偏移地址在BX中。
1. [BX]:bx中存放的数据作为一个偏移地址EA,读地址SA默认在ds中。
2. Loop指令
a) 格式: loop 标号。CPU执行loop时,要进行两步操作:
i. (cx)=(cx)-1;
ii. 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。
Loop指令来实现循环功能,cx中存放循环次数。
标号:标号代表一个地址,相当于给某个地址取个别名,而不用查找实际地址是多少。
需要loop循环的代码需要写在标号与loop之间。
注意:在汇编程序中,数据不能以字母开头,当数据开头含有A~E时需要在前面加上0.
G命令只运行到指定地址部分。(G 地址)
P命令使debug一次循环完loop,当(cx)=0为止。
3. debug和汇编编译器masm对指令的不同处理
mov ax,[0]
被编译器当做指令处理“mov ax,0”;
在debug中是将ds:[0]处得数据送入ax中。
如果在编译器中要将[address]当做地址来处理,则需要先将地址存入BX中,用[bx]的形式访问内存单元;或者显示指定ds,如:mov al,ds:[0]。
在汇编程序中,如果用指令访问一个内存单元,则在指令中必须用[..]来表示内存单元,若在[]里用一个常量idata直接给出内存单元的偏移地址,就要在[]的前面显示的给出段地址所在的段寄存器;如果没有显示给出段地址所在寄存器,编译器则会将指令中的[..]解释为数据。 也可使用bx进行中转,如:mov ax,[bx]。
4. loop 和[BX]的联合应用
在做加法时可能会出现两个问题:类型的匹配和结果的越界。
如何解决看似矛盾的问题? 将内存中的8位数据复制到一个16为寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配并且不会越界(ax的高8位为0,mov ah,0)。
可以将常量放入bx,然后通过[bx]来循环读出内存数据。Inc bx来得到下一个偏移地址。
5. 一段安全的空间
在8086模式中,随意向一段内存空间写入内容是很危险的,因为这段空间中可能存放着重要的系统数据和代码。
系统管理所有的资源,若我们需要向内存空间写入数据的话,要使用操作系统给我分配的空间,而不应直接用地址任意指定内存单元。一般dos和其他合法程序不会使用0:200~0:2ff(00200h~002ffh)的256个字节空间,所以这段空间是安全的。为了谨慎起见,使用debug查看该段空间是否全为0。
包含多个段得程序
内存中有256个字节是相对安全的空间,若超过256字节怎么办呢? 在操作系统的环境中,合法地通过系统取得的空间都是安全的,因为操作系统不会让一个程序所用的空间和其他程序及系统自己的空间相冲突。在操作系统允许的情况下,程序可以取得任意容量的空间。
程序取得所需空间有两种方法:
在加载程序的时候为程序分配;
程序在执行的过程中向兄申请。
若要在程序加载的时候能获取到所需空间,则就要在源程序中作出说明。通过在源程序中定义段来获取空间。
1. 在代码段中使用数据
定义数据:
Dw data1, data2, data3
当定义在代码段中时,数据的段地址就是CS,并且出入段得最开始处。
Assume cs:code
Code segment
数据定义
Start:
代码定义
Code ends
End start——告诉CPU执行程序的入口点,即:第一条执行指令的位置。
2. 在代码段中使用栈
定义为值为0的数据,将此数据的所占有的内存空间当做栈使用。此举又叫做开辟空间。
Assume cs:code
Code segment
Dw 0123h,0456h
Code ends
end
3. 将数据、代码、栈放入不同的段
一个段的最大容量是64kb(受CPU的位宽影响),当数据、栈和代码需要的空间超过64kb就不能放在一个段中。所以应该考虑用多个段来存放数据、代码和栈。
定义段得格式都是:(不论定义的是数据、代码、栈都是如此格式,使用的时候通过段名获得段地址)
Sname segment
段内容
Sname ends
访问段内存需要段地址和偏移地址,段地址由段名可得到,偏移地址就要看它在段中的位置了。不能直接将一个段地址传送到段寄存器中,需要使用通用寄存器中转(一般使用ax);因为段名会被编译器处理为一个代表段地址的数值。
使用伪指令 assume cs:code,ds:data,ss:stack 将cs、ds、ss分别和code、data、stack段相连,使用该伪指令将定义的具有一定用途的段和相关的寄存器联系起来。当使用code、data、stack时会自动用cs、ds、ss保存段地址。