[bx]与loop指令
1.[bx]与loop指令概念
[bx]
的含义:[bx]同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中[...]
的含义:[]表示内存单元,偏移地址是…关于[bx]与[…]的区别:主要就在于[…]是直接给偏移地址,而[bx]偏移地址在bx中
mov ax,[0] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址为0,段地址在ds中 mov al,[0] ;将一个内存单元内容送入al,这个内存单元长度为1字节,偏移地址为0,段地址在ds中 mov ax,[bx] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在ds中 mov al,[bx] ;将一个内存单元内容送入al,这个内存单元长度为1字节,偏移地址在bx中,段地址在ds中
loop
指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作:
- (cx) = (cx) - 1,这里的()是一个描述符,用来表示一个寄存器或一个内存单元中的内容,比如20000H表示20000H单元,(20000H)表示该单元下的内容
- ()中的元素可以是:寄存器名、段寄存器名、内存单元的物理地址
- 判断 cx 中的值,不为零则转至
标号
处执行程序,如果为零则向下执行例如:计算212
assume cs:code code segment mov ax, 2 mov cx, 11 ;循环次数 s: add ax, ax ;放置标号s loop s ;在汇编语言中,标号代表一个地址,标号s实际上标识了一个地址, ;这个地址处有一条指令:add ax,ax。 ;执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前 ;转至s处执行add ax,ax。所以,可以利用cx来控制add ax,ax的执行次数。 mov ax,4c00h int 21h code ends end
2.[bx]和loop的联合应用
例题:计算ffff:0 ~ ffff:b
单元中的数据的和,结果存储在dx中
问题分析:
运算后的结果是否会超出dx所能存储的范围?
分析:可以,ffff:0~ffff:b内存单元中的数据是字节型数据,范围在0 ~ 255之间,12个这样的数据相加,结果不会大于65535,可以在dx中存下
能否将ffff:0~ffff:b中的数据直接累加到dx中?
分析:不行,因为ffff:0~ffff:b中的数据是8位,不能直接加到16位寄存器dx中
能否将ffff:0~ffff:b中的数据累加到dl中,并设置(dh)=0,从而实现累加到dx中?
分析:不行,因为dl是8位寄存器,能容纳的数据范围在0 ~ 255之间,ffff:0~ffff:b中的数据也都是8位,如果仅向dl中累加12个8位数据,很可能造成进位丢失
我们如何将ffff:0~ffff:b中的8位数据,累加到16位寄存器dx中?
解决方案:用一个16位寄存器来做中介。将内存单元中的8位数据赋值到一个16位寄存器a中,再将ax中的数据加到dx
;解决方案代码 assume cs:code code segment mov ax,0ffffh ;在汇编源程序中,数据不能以字母开头,所以要在前面加0 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.段前缀概念
mov ax, ds:[bx] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在ds中 mov ax, cs:[bx] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在cs中 mov ax, ss:[bx] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在ss中 mov ax, es:[bx] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在es中 mov ax, ss:[0] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址为0,段地址在ss中 mov ax, cs:[0] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址为0,段地址在cs中
这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的
“ds:”,“cs:”,“ss:”,“es:”
,在汇编语言中称为段前缀关于安全段空间的扩展:
- 在一般PC机中,DOS方式下,DOS和其他合法程序一般都不会使用0:200~0:2ff(00200H ~ 002ffH)的256个字节的空间,所以我们使用这段空间是安全的
- 为了谨慎起见,进入DOS后,先用debug查看一下,如果0:200~0:2ff单元的内容都是0,则证明DOS和其他合法程序没有使用这里
段前缀的使用:将内存
ffff:0 ~ ffff:b
单元中的数据复制到0:200 ~ 0:20b
单元中assume cs:code code segment mov ax, 0ffffh mov ds, ax ;(ds)= 0ffffh mov ax, 0020h mov es, ax ;(es)= 0020h 0:200 等效于 0020:0 mov bx, 0 ;(bx)= 0,此时ds:bx指向ffff:0,es:bx指向0020:0 mov cx,12 ;(cx)=12,循环12次 s: mov dl,[bx] ;(d1)=((ds)* 16+(bx)),将ffff:bx中的字节数据送入dl mov es:[bx],dl ;((es)*16+(bx))=(d1),将dl中的数据送入0020:bx inc bx ;(bx)=(bx)+1 loop s mov ax,4c00h int 21h code ends end
4.包含多个段的程序案例
包含多个段的程序使用案例:
程序中对段名的引用,将被编译器处理为一个表示段地址的数值,如下
mov ax, data mov ds, ax mov bx, ds:[6]
在代码段中使用数据,如下:
;计算 8 个数据的和存到 ax 寄存器 assume cs:code code segment dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;dw含义是定义字型数据,即define word ;这8个数,偏移为:0、2、4、6、8、A、C、E 地址为:CS:0、CS:2、CS:4、CS:6、CS:8、CS:A、CS:C、CS:E start: mov bx, 0 ;标号start mov ax, 0 mov cx, 8 s: add ax, cs:[bx] add bx, 2 loop s mov ax, 4c00h int 21h code ends end start ;end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方 ;用end指令指明了程序的入口在标号start处,也就是说,“mov bx,0”是程序的第一条指令。
在代码段中使用栈,如下:
;利用栈,将程序中定义的数据逆序存放 assume cs:codesg codesg segment dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ; 0-15单元 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 16-47单元作为栈使用 start: mov ax, cs mov ss, ax mov sp, 30h ;将设置栈顶ss:sp指向栈底cs:30。 30h = 48d mov bx, 0 mov cx, 8 s: push cs:[bx] add bx, 2 loop s ;以上将代码段0~15单元中的8个字型数据依次入栈 mov bx, 0 mov cx, 8 s0: pop cs:[bx] add bx,2 loop s0 ;以上依次出栈8个字型数据到代码段0~15单元中 mov ax,4c00h int 21h codesg ends end start ;指明程序的入口在start处
将数据、代码、栈放入不同的段,如下:
assume cs:code,ds:data,ss:stack data segment dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;0-15单元 data ends stack segment dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;0-31单元 stack ends code segment start: mov ax, stack;将名称为“stack”的段的段地址送入ax mov ss, ax mov sp, 20h ;设置栈顶ss:sp指向stack:20。 20h = 32d mov ax, data ;将名称为“data”的段的段地址送入ax mov ds, ax ;ds指向data段 mov bx, 0 ;ds:bx指向data段中的第一个单元 mov cx, 8 s: push [bx] add bx, 2 loop s ;以上将data段中的0~15单元中的8个字型数据依次入栈 mov bx, 0 mov cx, 8 s0: pop [bx] add bx, 2 loop s0 ;以上依次出栈8个字型数据到data段的0~15单元中 mov ax, 4c00h int 21h code ends end start ;“end start”说明了程序的入口,这个入口将被写入可执行文件的描述信息, ;可执行文件中的程序被加载入内存后,CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令