汇编语言学习——第五章 [BX] 和LOOP 指令

来源:互联网 发布:交大网络教育学院登录 编辑:程序博客网 时间:2024/05/22 01:56

1、关于[BX]

[BX]用来表示一个内存单元的偏移地址,段地址默认在DS中取得。

一条简单指令的功能:

mov ax,[bx]

功能:bx 中存放的数据作为一个偏移地址EA ,段地址SA 默认在DS 中,将SA:EA处的数据送入ax中。

即: (ax)=(ds *16 +(bx));

 

2、 LOOP指令

指令的格式是:loop 标号,CPU 执行loop指令的时候,要进行两步操作:

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

CX中的值影响着loop指令的执行结果,CX 中存放循环次数。

 

编程计算2^12

ASSUME CS:CODESG
CODESG SEGMENT
START:
        MOV AX,2
        MOV CS, 11


S:     ADD AX, AX
        LOOP S

        MOV AX, 4C00H  ; 程序的返回。
        INT 21H


CODESG ENDS
END START

 

程序分析:

(1)标号

在汇编语言中,标号代表一个地址,此程序中有一个标号s 。

它实际上标识了一个地址,这个地址处有一条指令:add ax,ax。

(2)loop s

    CPU 执行loop s的时候,要进行两步操作:
    ① (cx)=(cx)-1;
    ② 判断cx 中的值,不为0 则转至标号s 所标识的地址处执行(这里的指令是“add ax,ax),

         如果为零则执行下一条指令(下一条指令是mov ax,4c00h)。

    我们可以利用cx来控制add ax,ax的执行次数。

 

用cx和loop 指令相配合实现循环功能的三个要点:
(1)在cx中存放循环次数;
(2)loop 指令中的标号所标识地址要在前面;
(3)要循环执行的程序段,要写在标号和loop 指令的中间。

用cx和loop指令相配合实现循环功能的程序框架如下:

    mov cx,循环次数
 s:
    循环执行的程序段
    loop s

 

3、编程问题。

计算ffff:0006单元中的数乘以3,结果存储在dx中。程序如下:

ASSUME CS:ABC

ABC SEGMENT

START:

        MOV AX, 0FFFFH

        MOV DS, AX

        MOV BX, 0006H

        MOV AH, 0

        MOV AL, [BX]

        MOV DX, 0

        MOV CX, 3

S:

        ADD DX, AX

        LOOP  S

 

         MOV AX, 4C00H

         INT 21H

ABC ENDS

END START

 

分析:

注意程序中的第一条指令mov ax,0ffffh。

我们知道大于9FFFH的十六进制数据A000H、A001H、…… 、C000H、C001H等,

在书写的时候都是以字母开头的。

而在汇编源程序中,数据不能以字母开头,所以要在前面加0。

 

注:在调试LOOP指令时,可以用G命令或P命令跳过循环。

 

4、Debug和汇编编译器MASM的不同

1)在Debug中,输入的数值,默认是16进制,而在源程序中,默认是10进制,表示16进制要加‘H'

2)偏移地址的表示不同。

在Debug中,要将ds:0处的数据送入al中。指令是 MOV AL,[0]

在汇编源程序中,指令是 MOV BX, 0   MOV AL,[BX]

如果直接 mov ax,[0] ,那么将被编译器当作指令 “mov ax,0” 处理。

 

在MASM中mov ax, [2]是解释为mov ax,2的。一般我们是通过BX来代替,

先 mov bx, 2  再通过mov ax, [bx]来实现。

如果要像DEBUG一样直接用[2]的话,那么一定要加上段地址! MOV AX,DS:[0],段前缀 

 

5、loop和[bx]的联合应用

计算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位寄存器,能容纳的数据的范围在小 255 之间,ffff : 0~ffff:b中的数据也都是 8 位,如果仅向dl中累加12个 8 位数据,很有可能造成进位丢失。

 

解决的一种思路是:用一个16位寄存器来做中介。

我们将内存单元中的 8 位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配并且结果不会超界

汇编代码如下:

ASSUME CS:CODESG

CODESG SEGMENT

START:

        MOV AX, 0FFFFH   ; 一定要加上0

        MOV DS, AX

        MOV BX, 0

        MOV CX, 12    ; 循环的次数是12次

        MOV DX, 0

S:

        MOV AL, [BX]

        MOV AH, 0

        ADD DX, AX

        INC  BX     ; 指向下一个字节单元。

        LOOP S

 

        MOV AX, 4C00H

        INT 21H

CODESG ENDS

END START

 

6、一段安全的空间

在8086模式中,随意向一段内存空间写入内容是很危险的 ,因为这段空间中可能存放着重要的系统数据或代码。

为了避免冲突,我们需要有一段内存空间可以供我们编程使用。

在一般的PC机中,DOS方式下,DOS和其他合法的程序一般都不会使用0:200~0:2FF( 0:200h~0:2FFh)的256 个字节的空间。

所以,我们使用这段空间是安全的。

为什么DOS和其他合法的程序一般都不会使用0:200~0:2FF这段空间?暂时不明白,接下来的学习可能会讲解到这个问题。

由于在DOS方式下,一般情况, 0:200~0:2FF 空间中没有系统或其他程序的数据或代码;
所以我们需要直接向一段内存中写入内容时,就使用0:200~0:2FF这段空间

 

7、另外一个编程题

将内存ffff:0~ffff:b段元中的数据拷贝到 0:200~0:20b单元中。

代码一:

ASSUME CS:CODESG
CODESG SEGMENT
START:
         MOV BX, 0       ; 偏移地址
         MOV CX, 12     ; 确定循环的次数

S:      MOV AX, 0FFFFH;
         MOV DS, AX
         MOV DL, [BX]  ;  // 因为是字节单元,8位,所以是 DL 
         MOV AX, 0020H
         MOV DS, AX
         MOV [BX],DL ; 
         INC BX            ; BX自增一,指向下一个字节单元

         LOOP S

         MOV  AX, 4C00H   ; 程序返回。

         INT 21H

CODESG  ENDS
END START

 

使用两个寄存器进行改进。

ASSUME CS:CODESG
CODESG SEGMENT
START:
         MOV BX,0
         MOV CX,12
         MOV AX,0FFFFH
         MOV DS,AX
         MOV AX, 0020H
         MOV ES, AX         ; 这里多了一个段寄存器ES

 

S:      MOV DL,[BX]
         MOV ES:[BX],DL  ; 这里显示地指出了地址 ES:[BX]
         INC BX
         LOOP S

         MOV AX, 4C00H
         INT 21H
CODESG ENDS
END START

 

个人总结: 我觉得本章的重点主要是[bx]的理解,loop的熟悉和运用,区分Debug命令和汇编源程序的不同,

以及对一段安全空间的认识。

原创粉丝点击