[BX]和Loop指令

[…]的规定与(…)的规定

一个内存单元的描述:

  • 内存单元的地址
  • 内存单元的长度

[…]–表示一个内存单元
(…)–表示一个内存单元或寄存器中的内容

描述对象描述结果
ax的内容为0010H(ax)=0010H
2000:1000处的内容为0010H(21000H)=0010H
对于mov ax,[2]的功能(ax)=((ds)*16+12)
对于mov [2],ax的功能((ds)*16+12)=(ax)
对于add ax,2的功能(ax)=(ax)+2
对于add ax,bx的功能(ax)=(ax)+(bx)
对于push ax的功能(sp)=(sp)-2 ((ss)*16+(sp))=(ax)
对于pop ax的功能(ax)=((ss)*16+(sp) (sp)+2= (sp)

符号idata表示常量

Ag:
mov ax,[idata]:代表 mov ax,[1] 、 mov ax,[2]、mov ax,[3]…
mov bx,idata:代表mov bx,1、mov bx,2、mov bx,3…
mov ds,idata 这种对于段位寄存器的操作是非法的

补充指令:inc 表示给寄存器里的值加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)

Loop指令

首先Loop这个单词具有循环;回路…的意思
在计算机中就行明显了就是循环
功能:实现循环(计数型循环)
指令的格式
loop标号
CPU执行Loop指令时要进行的操作

  1. (cx)=(cx)-1;
  2. 判断cx中的值不为零则转至标号处执行程序
    如果为零则向下执行

看一段代码
assume cs:code
code segment
mov ax,2
mov cx,11
s: add ax,ax
loop s
mov ax,4c00H
int 21H
code ends
end
分析一下:
在这个代码中
我们注意到s:add ax,ax这一段,看到s,这是loop指令定义的标识符号
要求:

  1. cx中提前存放循环的次数,因为(cx)影响着loop指令的执行结果
  2. 要定义一个标号(s)

上面这段代码,我们实现的是计算2^12次方
add ax,ax就可以实现

用cx和Loop指令相配合实现循环功能的三个要点:

  1. 在cx中存放循环的次数
  2. 用标号指定循环开始的位置
  3. 在标号和loop指令的中间,写上要循环执行的程序段

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

计算ffff:0006单元中的数乘以3,结果存储在dx中
分析一下问题:

  1. 运算后的结果是否会超出dx所能存储的范围?
  2. 用循环累加来实现乘法,用哪个寄存器进行累加?
  3. ffff:6单元是一个字节单元,ax是一个16位寄存器,数据的长度不一样如何赋值?
    程序:
    assume cs:code
    code segment
    mov ax,0ffffH \(在汇编程序中数据不能以字母开头要ffff前0)
    mov ds,ax
    mov bx,6
    mov al,[bx]
    mov ah,0
    \ (ax)=((ds)*16+(bx))
    mov dx,0
    mov cx,3 \设置次数
    s: add dx,ax\结果在dx中
    loop s
    mov ax,4c00H
    int 21H
    code ends
    end
    解决问题:
    1: ffff:0006单元中的数是一个字节型的数据,范围在0~255之间,则用它和3相乘结果不会大于65535,可以在dx中存放下
    2:将ffff:0006单元中的数赋值给ax,用dx进行累加。先设(dx)=0,然后做3次(dx)=(dx)+(ax)
    3:注意,我们所说的“赋值”,就是说,让ax中的数据的值(数据的大小)和ffff:0006
    单元中的数据的值(数据的大小)相等。8位数据01H和16位数据0001H的数据长度不一样,但它们的值是相等的。
    那么我们如何赋值?设ffff:0006单元中的数据是XXH,若要ax中的值和ffff:0006单元中的相等,ax中数据应为00XXH。所以,若实现ffff:0006单元向ax赋值,应该令(ah)=0,(al)=(ffff6H)
    在这里插入图片描述
    之前我们讲述过p命令和G命令这里不坐重复
    用p命令当我们在执行循环的时候,我们可以跳过循环
    用g命令我们可以从指定位置执行命令
    示范:
    在这里插入图片描述当然我们也可以用G命令执行倒数第二步,上面重复的命令直接结束

结果
在这里插入图片描述

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

  1. 在Debug中编程实现:
    mov ax,2000
    mov ds,ax
    mov al,[0]
    mov bl,[1]
    mov cl,[2]
    mov dl,[3]
  2. 汇编源程序实现:
    assume cs:code
    code segment
    mov ax,2000h
    mov ds,ax
    mov al,[0]
    mov bl,[1]
    mov cl,[2]
    mov dl,[3]
    mov ax,4c00h
    int 21h
    code ends
    end

看一看下这两的实施情况
在这里插入图片描述在这里插入图片描述

由上述两幅图,我们可以看到,Debug和编译器masm对形如“mov ax,[0]”这类命令在解释上不同

从上述第二幅图,这样写是不能送入内存单元的内容的
问题:那么我们如何在源程序中实现将内存2000:0、2000:1、2000:3单元中的数据送入al,bl,cl,dl中呢?
两种方法:

  1. mov ax,2000h
    mov ds,ax
    mov bx,0
    mov al,[bx]
  2. mov ax,2000h
    mov ds,ax
    mov al,ds:[0]

根据方法二我们可以理解加上段地址后跟上偏移地址就可以得到该内存单元内我们想要的
注意是段位寄存器,也就是说除了,ds还可以用ss、es…,也称之为段前缀

Loop和[bx]的联合应用

思考:计算ffff:0~ffff:b单元中的数据的和,结果存储在dx中
分析问题:

  1. 运算后的结果是否会超过dx所能承受的范围?
  2. 我们能否将ffff:0~ffff:b中的数直接累加到dx中?
  3. 我们能否将ffff:0~ffff:b中的数据累加到dl中,并设置(dh)=0,从而实现累加到dx中?
  4. 我们到底怎样将ffff:f~ffff:b中的8位数据,累加到16位寄存器dx中?

再分析过后,有两种方法:
(1)(dx)=(dx)+内存中的8位数据
(2)(dl)=(dl)+内存中8位数据
第一种方法类型不匹配
第二种方法很可能造成进位丢失
那怎么解决?
目前:用一个16位寄存器来做中介。将内存单元中8位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配并且不会超界
程序:
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov dx,0
mov al,ds:[0]
mov ah,0
add dx,ax
mov al,ds:[1]
mov ah,0
add dx,ax
mov al,ds:[2]
mov ah,0
add dx,ax
mov al,ds:[3]
mov ah,0
add dx,ax
mov al,ds:[4]
mov ah,0
add dx,ax
mov al,ds:[5]
mov ah,0
add dx,ax
mov al,ds:[6]
mov ah,0
add dx,ax
mov al,ds:[7]
mov ah,0
add dx,ax
mov al,ds:[8]
mov ah,0
add dx,ax
mov al,ds:[9]
mov ah,0
add dx,ax
mov al,ds:[0ah]
mov ah,0
add dx,ax
mov al,ds:[0bh]
mov ah,0
add dx,ax
mov ax,4c00h
int 21h
code ends
end
看到上面这一长串代码,大概已经想到了loop命令,因为有重复的,而且要是程序这样去写,如果我们换一个长一点的进行计算,效率很低!
分析这个代码
mov al,ds:[x]
mov ah,0
add dx,ax
那么如果我们能用一个循环,x的值从0到11执行12次就好了
程序:
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov dx,0
mov cx,12
s: mov al,[bx]
mov ah,0
add dx,ax
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
从这里我们也能学习到对于同一问题有不同的解决方法,更重要是效率,除了汇编,其他的语言都是如此!!!

一段安全的空间

在8086模式中,随意向一段内存空间写入内容是很危险的,因为这段空间中可能存放着重要的系统数据或代码。
Ag:
assume cs:code
code segment
mov ax,0
mov ds,ax
mov ds:[26h],ax
mov ax,4c00h
int 21h
code ends
end
在这里插入图片描述当我们写道这里就动不了,因为这里我用的模拟机。
其实这里指令无效,因为这段地址我们不能写入东西,CPU没有开保护,现在被我们改写了,用不了了
注意:
我们在纯DOS方式(实模式)下,可以不理会DOS,直接用汇编语言去操作真实的硬件,因为运行在CPU实模式下的DOS,没有能力对硬件系统全面、严格的管理。但在Windows2000、Unix这些运行与CPU保护模式下的操作系统中,不理会操作系统,用汇编语言去操作真实的硬件,根本不可能的。硬件已被这些操作系统利用CPU保护模式所提供得到功能全面而严格管理了
现在我们只需要知道,0:200~0:2ff的256个字节的空间是安全的

总结:

  1. 我们需要直接向一段内存中写入内容
  2. 这段内存空间不应该存放系统或其他程序的数据或代码,否则写入操作很可能引发错误
  3. DOS方式下,一般情况0:200~0:2ff空间中没有系统或其他程序的数据或代码
  4. 以后,我们需要直接向一段内存中写入内容时,就使用0:200~0:2ff这段空间

段前缀的使用

思考:将内存ffff:0~ffff:b单元中的数据复制到0:200~0:20b单元中
程序:
assume cs:code
code segment
mov bx,0 ;(bx),偏移地址从0开始
mov cx,12;(cx)=12,循环12次
s:mov ax,0ffffh
mov ds,ax ;(ds)=0ffffh
mov dl,[bx] ; (dl)=((ds)*16+(bx)),将ffff:bx中数据送入al
mov ax,0020h
mov ds,ax ; (ds)=0020h
mov [bx],dl; ((ds)*16+(bx))=(dl),将dl的数据送入0020:bx
inc bx ; (bx)=(bx)+1
loop s
mov ax,4c00h
int 21h
code ends
end
从这个程序来看,我们每次循环都要改变ds的值,每次循环还都要设置两次ds的值。直接影响我们的效率
程序:
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,12
s:mov dl,[bx]
mov es:[bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Back~~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值