BX和Loop

Reverse

bx 寄存器和 loop 循环的学习小结🛰️

符号和常量

描述性符号"( )"

使用"( )"来表示一个寄存器或一个单元中的内容

“( )”中的元素有3种类型

  • 寄存器名
  • 段寄存器名
  • 内存单元的一个物理地址(一个20位的数据)

例如:(ax)、(20002h)、((ds)*16+(bx))

idata 常量

就是表示一个常量,没啥好解释的。

例如:

1
2
mov ax,[idata] 就代表 mov ax,[1]、mov ax,[2] 等
mox bx,idata 就代表 mov bx,1、mox bx,2 等

[BX]

什么是[bx]

bx是一个通用寄存器的代号,当 bx 变成 [bx] 时,bx 的值就不单单代表着数值,它还表示着偏移地址。

如何运作

举个例子

  • mov ax,[bx]

功能:bx中所存放的数据作为一个偏移地址,然后再结合 ds 中段地址的数据计算出物理地址

1
物理地址=(ds)*16+bx

然后将该物理地址中的数据送入 ax 中。

Loop

什么是 Loop

loop 中文意思是:循环。

作用也就很明显了,它就相当于我们最常接触的 while 和 for,循环的一个关键是循环的次数,而在汇编语言中 loop 所循环的次数是由 cx 所决定的。

格式以及运作原理

格式如下:

1
2
3
4
5
6
7
8
...
...
s:xxx
xxx
loop s
xxx
...
...
  • 标号 s 要放在 loop 指令之前
  • 循环执行的程序段放在标号和 loop 指令之间

运作原理:

当 CPU 执行 loop命令时会执行一下两个步骤:

  1. (cx)=(cx)-1
  2. 判断 cx 的值是否为0,如果不为0,则跳转至 s 处继续执行代码;如果为零,那就继续执行下一条指令

两者的联合使用

当我们需要对连续性变化的内存地址进行重复性的操作时,如果我们不适用循环,那我们的源码会变得十分冗长,且有很多的重复性语句。

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

首先我们最应该考虑的是数据是否会溢出,数据类型是不是匹配等问题。很显然,溢出的问题是不存在的,但是将 ffff:0 中的数据直接放入 bx 中是不可取的,因为前者的数据是8位,而后者的数据是16位。

通过如下步骤解决问题

1
2
mov al,ds:[0] //将目标数据放入低位的 ax 寄存器中
mov ah,0 //将 ax 寄存器的高位置为0,此时(ax)=(ffff:0)且数据长度为16位

不利用循环的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
assume cs:code
code segment

mov ax,0ffffh //汇编语言中不允许字母为开头的常量,所以我们添加0
mov ds,ax //设置(ds)=ffffh
mov dx,0 //初始化累加器

mov al,ds:[0]
mov ah,0 //获取目标内存中的数据且长度为16位
add dx,ax //进行数据累加

mov al,ds:[1]
mov ah,0
add dx,ax

.
.
.

mov al,ds:[0bh]
mov ah,0
add dx,ax

mov ax,4c00h //程序返回
int 21h

code ends
end

该程序中间的实现功能的主要部分大多都是相似的,变化的不过时偏移地址的值,因此我们在循环中改变偏移地址的值即可。

使用循环的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
assume cs:code
code segment

mov ax,0ffffh //汇编语言中不允许字母为开头的常量,所以我们添加0
mov ds,ax //设置(ds)=ffffh
mov dx,0 //初始化累加器

mov cx,12 //设置循环为12次

s: mov al,[bx]
mov ah,0
add dx,ax //将目标数据存入ax中并累加
inc bx //改变偏移地址
loop s

mov ax,4c00h //程序返回
int 21h

code ends
end

本文作者:GhDemi

本文链接: https://ghdemi.github.io/2022/05/24/BX%E5%92%8CLoop/

文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。