[BX] 和 loop 指令---汇编学习笔记

[BX] 和 loop 指令

  1. [bx]和内存单元的描述
  2. loop
  3. 我们定义的描述性的符号:“()”,“()”中的元素可以有3中类型:寄存器名、段寄存器名、内存单元的物理地址。
  4. 约定符号idata表示常量

5.1 [BX]

具体实例:

mov ax,[bx]

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

问题 5.1

程序和内存中的情况如下图所示,写出程序执行后,21000H~21007H单元中的内容。
内存情况
程序代码和结果如下:

mov ax,2000h        ;ax = 2000h
mov ds,ax           ;ds = 2000h
mov bx,1000h        ;bx = 1000h
mov ax,[bx]         ;ax = 00BEh
inc bx              ;bx = 1001h inc是将后面的内容+1
inc bx              ;bx = 1002h
mov [bx],ax         ;2000:1002 = 00BEh
inc bx              ;bx = 1003h
inc bx              ;bx = 1004h
mov [bx],ax         ;2000:1004 = 00BEh
inc bx              ;bx = 1005h
mov [bx],al         ;2000:1005 = BEh
inc bx              ;bx = 1006h
mov [bx],al         ;2000:1006 = BEh

5.2 Loop指令

loop指令格式:loop 标号

loop指令执行的时候,进行两步操作:(cx) = (cx) - 1 和 判断cx中的值,若不为0则转至标号处执行程序,若为0则向下继续执行程序(通俗的说,就是如果不为0继续循环,为0就退出)。

任务:

  1. 编程计算2^2
  2. 编程计算2^3
  3. 编程计算2^12

对于上面3个问题,如果我们进行重复输入指令去计算的话,会发现如果我们要计算一百次,就需要写几百行代码。所以我们引入了loop这个工具。

程序用loop实现:

assume cs:code

code segment

    mov ax,2

    mov cx,n    ;这里的n代表n+1次方

s:  add ax,ax   ;第一次add时,ax = 4 = 2^2
    loop s      

    mov ax,4c00h
    int 21h

code ends

end

问题 5.2

编程,用加法计算 123*236,结果存在ax中。

assume cs:code

code segment

    mov ax,0


    mov cx,123

m:  add ax,236
    loop m


    mov ax,4c00h
    int 21h

code ends

end

此时,效率达到最高。


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

考虑这样一个问题,计算ffff:0006单元中的数乘以3,结果存储在dx中。

我们分析一下:

  1. 运算后的结果是否会超出dx所能存储的范围?
    ffff:0006单元中的数是一个字节型的数据,范围0~255之间,则用它和3相乘结果不会大于65535,可以在dx中存放下。
  2. 用循环累加实现乘法,用哪个寄存器进行累加?
    将ffff:0006单元中的数赋值给ax,用dx进行累加。先设(dx) = 0,然后做3次(dx) = (dx) + (ax)。
  3. ffff:6单元是一个字节单元,ax是一个16位寄存器,数据的长度不一样,如何赋值?
    ax的低8位与ffff:6对其。

编写程序:

assume cs:code

code segment

    mov ax,0ffffh
    mov ds,ax
    mov bx,6

    mov al,[bx]
    mov ah,0

    mov dx,0

    mov cx,3

m:  add dx,ax
    loop m

    mov ax,4c00h
    int 21h

code ends

end

注意:在汇编源程序中,数据不能以字母开头

自行Debug调试。这里还有个g指令,可以直接跳到某个语句。格式为:g IP的地址


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

在Debug中编程实现:
这里写图片描述
汇编源程序实现:

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加载后:
这里写图片描述
我们发现,Debug将它解释为[idata],而编译器将[idata]解释为idata(也就是说,mov al ,[0] 等效于 (ax) = 0。[idata]表示常量,[bx]表示ds:[bx]。)


loop 和 [bx] 的联合应用

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

分析:

  1. 运算后的结果是否会超出dx所能存储的范围?
    ffff:0~b内存单元中的数据是字节型数据,范围在0~255之间,12个这样的数据相加,结果不会大于65535,可以在dx中存放下。
  2. 我们能否将ffff:0~b中的数据直接累加到dx中?
    当然不行,因为ffff:0~b中的数据是8位的,不能直接加到16位寄存器dx中。
  3. 我们能否将ffff:0~b中的数据累加到dl中,并设置(dh)=0,从而实现累加到dx中?
    不行,dl是8位寄存器,只能容纳0~255之间,可能会造成进位丢失。
  4. 我们到底怎样将ffff:0~b中的8位数据,累加到16位寄存器dx中?
    将8位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上。

程序代码如下:

assume cs:code
code segment

    mov ax,0ffffh
    mov ds,ax
    mov bx,0

    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

这就是bx与loop配合使用的一个典型例子。


5.6 段前缀

我们可以使用段地址:[偏移地址]的形式:

  1. mov ax,ds:[bx]
  2. mov ax,cs:[bx]
  3. mov ax,ss:[bx]
  4. mov ax,es:[bx]
  5. mov ax,ss:[0]
  6. mov ax,cs:[0]

以上的“ds:”、“cs:”、“ss:”、“es:”,在汇编语言中称为段前缀


5.7 一段安全的空间

我们执行以下程序:

assume cs:code
code segment

    mov ax,0
    mov ds,ax
    mov ds:[26h],ax

    mov ax,4c00h
    int 21h

code ends
end

运行后,发现报错:
这里写图片描述
这是由于0000:0026处存放的重要系统数据被修改而造成的

一般,合法的程序不会使用0000:0200~0000:02ff这段空间,所以对于我们来说,这段空间是安全的


5.8 段前缀的使用

将内存ffff:0~b单元中的数据复制到0:200~0:20b单元中。

分析:

(1)0:200~0:20b单元等同于0020:0~0020:b单元,它们描述的是同一段内存空间,
(2)复制的过程应用循环实现。
(3)在循环中,源始单元ffff:x和目标单元0200:x的偏移地址x是变量。用bx存放。
(4)将0:200~0:20b用0020:0~0020:b描述。

程序如下:

assume cs:code
code segment

    mov ax,0ffffh
    mov ds,ax

    mov ax,0020h
    mov es,ax

    mov bx,0h

    mov cx,12

m:  mov dl,[bx]
    mov es:[bx],dl
    inc bx
    loop m

    mov ax,4c00h
    int 21h

code ends
end

实验4 [bx]和loop的使用

(1)编程,向内存0:200~0:23F依次传送数据0~63(3FH)。

assume cs:code
code segment

    mov ax,20h
    mov ds,ax

    mov cx,40h

    mov bx,0

s:  mov [bx],bx
    inc bx
    loop s

    mov ax,4c00h
    int 21h

code ends
end

(2)编程,向内存0:200~0:23F一次传送数据0~63(3FH),程序中只能使用9条指令,9条指令中包括“mov ax,4c00h”和“int 21h”。

答案同上

(3)下面的程序的功能是将“mov ax,4c00h”之前的指令复制到内存0:200处,补全程序。上机调试,跟踪运行结果。

assume cs:code
code segment

    mov ax,076A
    mov ds,ax
    mov ax,0020h
    mov es,ax
    mov bx,0
    mov cx,1Bh
s:  mov al,[bx]
    mov es:[bx],al
    inc bx
    loop s

    mov ax,4c00h
    int 21h

code ends
end

提示:
(1)复制的是什么?从哪里到哪里?
复制的是指令,从076A:0开始到0020:0。
(2)复制的是什么?有多少个字节?你如何知道要复制的字节的数量?
有1B个字节。


本章完

猜你喜欢

转载自blog.csdn.net/qq_37340753/article/details/81284671