《汇编语言》- 读书笔记 - 第5章- [BX]和 loop 指令

  1. [bx]和内存单元的描述
指令 段地址 偏移地址 说明
mov ax, [0] ds 0 将内存 ds:0 处的单元中的内容,送入 ax
mov al, [0] ds 0 将内存 ds:0 处的字节单元中的内容,送入 ax 的低8位
mov ax, [bx] ds bx中的值 将内存 ds:[bx] 处的单元中的内容,送入 ax
mov al, [bx] ds bx中的值 将内存 ds:[bx]处的字节单元中的内容,送入 ax 的低8位
  1. loop
    loop 指令表示循环。

  2. 定义的描述性的符号:“()”
    书中约定:()括号用来表示寄存器内存中的内容。
    ()中可以入:寄存器名、段寄存器名、内存单元的物理地址。

(ax)表示 ax 中的内容;
(al)表示 al 中的内容;
(20000H)表示内存 20000H 单元的内容(()中的内存单元的地址为物理地址);
((ds)*16+(bx))表示:内层()从ds和bx取出值,算出结果后当用一个物理地址,外层()从内存地址取出内容。

  1. ax 中的内容为 0010H,可以这样来描述: (ax)=0010H;
  2. 2000:1000 处的内容为 0010H,可以这样来描述: (21000H)=0010H;
  3. 对于 mov ax,[2]的功能,可以这样来描述:(ax)=((ds)*16+2);
  4. 对于 mov [2],ax 的功能,可以这样来描述:((ds)*16+2)=(ax);
  5. 对于 add ax,2 的功能,可以这样来描述: (ax)=(ax)+2;
  6. 对于 add ax,bx 的功能,可以这样来描述:(ax)=(ax)+(bx);
  7. 对于 push ax 的功能,可以这样来描述:
(sp)=(sp)-2
((ss)*16+(sp))=(ax)
  1. 对于 pop ax 的功能,可以这样来描述:
(ax)=((ss)*16+(sp))
(sp)=(sp)+2
  1. 约定符号 idata 表示常量
    书中约定: idata 表示常量。
    书中约定便于沟通,并非真的合法指令。

mov ax,[idata] 就代表 mov ax,[1]mov ax,[2]mov ax,[3]
mov bx, idata 就代表 mov bx,1mov bx,2mov bx,3
mov ds, idata 就代表 mov ds,1mov ds,2

5.1 [BX]

mov ax, [bx]
功能: bx 中存放的数据作为一个偏移地址 EA,段地址 SA 默认在 ds 中,将 SA:EA处的数据送入 ax 中。
即: (ax)=((ds)*16+(bx)).

mov[bx], ax
功能: bx 中存放的数据作为一个偏移地址 EA,段地址 SA 默认在 ds 中,将 ax 中的数据送入内存 SA:EA 处。即:((ds)*16+(bx))=(ax)。

问题 5.1

程序和内存中的情况如图 5.1 所示,写出程序执行后,21000H~21007H 单元中的内容。
在这里插入图片描述

5.2 Loop 指令

通常使用 loop 实现循环功能, cx 中存放循环次数。指令的格式是: loop 标号

CPU 执行 loop 指令的时候,分两步:

  1. (cx)=(cx) - 1;
  2. 判断 cx != 0 则:转至标号处执行,否则:向下继续执行。

任务 1

编程计算 2^2,结果存在 ax 中。
在这里插入图片描述

任务 2

编程计算 2^3

mov ax, 2
add ax, ax
add ax, ax

任务 3

编程计算 2^12

mov ax, 2
add ax, ax ; 重复 11

用于引出 loop 循环

程序 5.1

assume cs:abc	
abc segment		
	mov ax, 2
	
	mov cx, 11	; 循环 11 次
 s: add ax, ax
	loop s		; cx-1 后如果不为 0,转到 s 处执行
	
	mov ax, 4c00H
	int 21H		
abc ends		
end

初始为 2 再 add ax, ax 11 次实现 2^12
在这里插入图片描述

问题 5.2

编程,用加法计算 123 * 236,结果存在 ax 中。
分析:可用循环完成,123 * 236 等于 123相加236次。

assume cs:abc	
abc segment		
	mov ax, 123
	mov cx, 236
 s: add ax, 123
	loop s		
	mov ax, 4c00H
	int 21H		
abc ends		
end

问题 5.2

改进程序 5.2,提高 123 * 236 的计算速度。
分析:123 * 236 等于 123相加236次。也可以是 236相加123次。

assume cs:abc	
abc segment		
	mov ax, 236
	mov cx, 123
 s: add ax, 236
	loop s		
	mov ax, 4c00H
	int 21H		
abc ends		
end

5.3 在 Debug 中跟踪用 loop 指令实现的循环程序

debug 中 t、p、g 的用法,不再赘述,详见:《汇编语言》- 读书笔记 - 实验1 查看 CPU 和内存,用机器指令和汇编指令编程

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

Debug

指令 说明
mov ax, [0] 将内存中 ds:0 的内容送进 ax

MASM

指令 说明
mov al, [0] (al)=0,将常量 0 送入 al中 (与 mov al,0 含义相同);
mov al, ds:[0] (al)=((ds)*16+0),将内存单元中的数据送入 al 中;
mov al, [bx] (al)=((ds)*16+(bx)),将内存单元中的数据送入 al 中;
mov al,ds:[bx] 等同 mov al, [bx]

总结:在masm中如果偏移以常量表示,则要显示指定段地址。

5.5 loop 和[bx]的联合应用

计算 ffff:0~ffff:B 单元中的数据的和,结果存储在 dx 中。
分析:

  1. dx放不放的下?
    答:0到b最多12个FF = 11EE,dx 有两字节最大存 FFFF,因此空间没问题。
  2. ffff:0~ffff:B的数能否直接在 dx中累加?
    答:不行。因为ffff:0~ffff:B中是字节。dx是字(占两个字节。)因为需要另一个寄存器做临时中转。
  3. 能否直接用 dl 累加?
    当然也不行。因为累加结果超过FF,只用dl会溢出。
    用临时工ax。比如 (al) = (ffff*16+0), (ah) = 0。把字节放进,值不变。

程序 5.5

assume cs:code
code segment
	mov ax, 0ffffh		;数值不能以字母开头,故前面加 0 
	mov ds, ax			;设置(ds)=ffffh
	
	mov dx, 0			;初始化累加寄存器,(dx)=0
	
	mov al, ds:[0]		;从内存取值,给临时工 ax。
	mov ah, 0			;清空高位
	add dx, ax			;执行累加
	
	; 累计操作共重复12次。	
	
	mov ax, 4c00h		
	int 21h
code ends
end

问题 5.4

程序5.5的代码有问题,重复多次,应该使用 loop 实现循环。

程序 5.6

assume cs:code
code segment
	mov ax, 0ffffh		;数值不能以字母开头,故前面加 0 
	mov ds, ax			;设置(ds)=ffffh
	mov bx, 0			;bx中存偏移地址,初始为 0
	
	mov dx, 0			;初始化累加寄存器,(dx)=0
	mov cx, 12			;设置循环次数
 s: mov al, [bx]		;从内存取值,给临时工 ax
	mov ah, 0			;清空高位
	add dx, ax			;执行累加
	inc bx				;bx+1让偏移地址指向下一个字节
	loop s				;检测循环条件,符合就循环,否则向下继续
	
	mov ax, 4c00h		
	int 21h
code ends
end

在这里插入图片描述

5.6 段前缀

mov ax, ds:[bx]
mov ax, cs:[bx]
mov ax, ss:[bx]
mov ax, es:[bx]
mov ax, ss:[0]
mov ax, cs:[0]

这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址ds:、cs:、ss、es 在汇编语言中称为段前缀

5.7 一段安全的空间

在一般的 PC 机中,DOS 方式下,DOS 和其他合法的程序一般都不会使用 0:200~0:2ff(00200h~002ffh)这 256 个字节的空间。
为了谨慎起见,在进入 DOS 后,我们可以先用Debug 查看一下,如果 0:200~0:2ff 单元的内容都是 0 的话,则证明确实没有人使用这里。

5.8 段前缀的使用

程序 5.8

书先写了一个不合理的版本,在循环中更改段前缀。引出后话。

程序 5.9

这次用两个段寄存器,分别破防源与目标。省去了循环中捣腾段寄存器的烦恼。

assume cs:code
code segment
	mov ax, 0ffffh
	mov ds, ax			; 设置源段前缀
	mov ax, 0020h
	mov es, ax			; 设置目标源段前缀
	
	mov bx, 0			; 偏移量从0开始(源和目标皆从0开始,正好共用)
	mov cx, 12			; 循环12次
 s:mov dl, ds:[bx]		; 从源内存取值,送入dl
	mov es:[bx], dl		; 从 dl 取值送入目标内存
	inc bx				; 偏移地址向前移动
	loop s				; 判断cx不为0就循环,否则继续向下。
	
	mov ax, 4c00h
	int 21h
code ends
end	

实验4 [bx]和 loop 的使用

《汇编语言》- 读书笔记 - 实验4 [bx]和 loop 的使用

猜你喜欢

转载自blog.csdn.net/jx520/article/details/130848963