汇编语言[王爽]-05 [BX]和loop指令
loop指令实现循环
执行过程:
①(cx)=(cx)-1
②判断 cx 中的值,不为零则转至标号处执行程序,如果为零则向下执行。
例:计算2^12
assume cs:codeseg
codeseg segment
mov ax,2
#-------做11次add ax,ax----------
mov cx,11
s:
add ax,ax
loop s
#--------------------------------
mov ax,4c00h
int 21h
codeseg ends
end
框架
mov cx,循环次数
s:
循环的程序段
loop s
考虑这么一个问题:计算ffff:0006单元中的数乘以3,结果储存在dx中
分析:
- 结果不能储存在一个8位的寄存器中,存在越界的可能,存在16位的寄存器中显然则不会越界,所以需要存在dx中而不是dl或者dh
- 基本思路:dx=0,把(ffff:0006)中的字节型数据放入ax中,执行三次
add dx,ax
- 八位的内存单元如何给16位的ax赋值? 令(ah)=0,赋值给al
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov bx,6h
mov ah,0
mov al,[bx]
mov dx,0
mov cx,3
s:
add dx,ax
loop s
mov ax,4c00h
int 21h
code ends
end
当写入 mov al,[dx]
时,编译器报错
debug调试循环的方式
g ip地址
: 直接执行到某条指令
p
: 可以用来结束int 21h,也可以用来跳过循环
注:debug调试程序时,文件名要带上后缀 -debug p.exe
Debug和汇编编译器masm对指令的不同处理
mov ax,[0]
Debug解释为 mov ax,((ds)*16+0)
masm解释为 mov ax,0
所以在masm要写为
# 显示指明段前缀
mov ax,ds:[0]
# 用寄存器
mov bx,0
mov ax,[bx]
loop 和 [bx]的联合运用
考虑这样一个问题,计算ffff:0 ~ ffff:b 单元中的数据的和,结果储存在bx中
8位数据存入al,以ax为中转赋值给bx【bx不会越界进位】
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov bx,0 ;初始化ds:bx指向ffff:0
mov dx,0 ;初始化累加器dx, (dx)=0
mov cx,12 ;初始化循环计数寄存器cx
s:
mov ah,0
mov al,ds:[bx] ;ax为中介传递数据
add dx,ax
inc bx ;ds:bx指向下一个元素
loop s
mov ax,4c00h
int 21h
code ends
end
一段安全的空间
assume cs:code
code segment
mov ax,0
mov ds,ax
mov ds:[26h],ax
mov ax,4c00h
int 21h
code ends
end
执行上述的程序,系统会死机
因为在实模式下,我们可以自由地操纵真实的硬件;
在保护模式下,则是在操作系统的保护下,无法操纵真实的硬件
所以在实模式下编程时,要使用安全的内存空间
一般是 0:200 ~ 0:2ff
这256字节的空间
段前缀的使用
考虑一个问题,把内存ffff:0 ~ ffff:b中的数据复制到 0:200 ~ 0:20b中
assume cs:code
code segment
;设置两个段前缀
mov ax,0ffffh
mov ds,ax
mov ax,20h
mov es,ax
mov bx,0
mov cx,12
s:
mov dl,ds:[bx]
mov es:[bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
为什么要使用 dl
而不是 mov es:[bx], ds:[bx]
因为 直接mov的话,没有指定内存大小,会报错
其实可以用 dx
但是那样的话 bx就不是 inc
而是 add bx,2