[bx]与loop指令

[bx]与loop指令


1.[bx]与loop指令概念

  1. [bx] 的含义:[bx]同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中
  2. [...]的含义:[]表示内存单元,偏移地址是…

关于[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指令的时候,要进行两步操作:

  1. (cx) = (cx) - 1,这里的()是一个描述符,用来表示一个寄存器或一个内存单元中的内容,比如20000H表示20000H单元,(20000H)表示该单元下的内容
  2. ()中的元素可以是:寄存器名、段寄存器名、内存单元的物理地址
  3. 判断 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中

问题分析:

  1. 运算后的结果是否会超出dx所能存储的范围?

    分析:可以,ffff:0~ffff:b内存单元中的数据是字节型数据,范围在0 ~ 255之间,12个这样的数据相加,结果不会大于65535,可以在dx中存下

  2. 能否将ffff:0~ffff:b中的数据直接累加到dx中?

    分析:不行,因为ffff:0~ffff:b中的数据是8位,不能直接加到16位寄存器dx中

  3. 能否将ffff:0~ffff:b中的数据累加到dl中,并设置(dh)=0,从而实现累加到dx中?

    分析:不行,因为dl是8位寄存器,能容纳的数据范围在0 ~ 255之间,ffff:0~ffff:b中的数据也都是8位,如果仅向dl中累加12个8位数据,很可能造成进位丢失

  4. 我们如何将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:”,在汇编语言中称为段前缀

关于安全段空间的扩展:

  1. 在一般PC机中,DOS方式下,DOS和其他合法程序一般都不会使用0:200~0:2ff(00200H ~ 002ffH)的256个字节的空间,所以我们使用这段空间是安全的
  2. 为了谨慎起见,进入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个数,偏移为:02468、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 0000000000000000 ; 16-47单元作为栈使用

	start:	mov ax, cs 
			mov ss, ax 
			mov sp, 30h ;将设置栈顶ss:sp指向栈底cs:3030h = 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:2020h = 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被设置指向这个入口,从而开始执行程序中的第一条指令

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值