8086汇编学习笔记07

汇编与简单计算

系列文章

[BX]和对内存单元的描述

[0] 表示内存单元,它的偏移地址是0。 [BX] 同样表示一个内存单元,它的偏移地址是 (BX)

例如,“ MOV AX, [BX] ”指令会将 DS:BX 指向内存单元中的数据移到寄存器 AX 上。

INC指令和LOOP指令

INC指令(自增指令)
格式:
INC container
用途:
container 对应的寄存器或存储空间中的值增加1。

这个指令比 ADD 指令的执行速度快,且占用空间小。

LOOP指令(循环指令)
格式:
LOOP label
用途:
CPU执行 LOOP 指令时,需要进行两步操作:
  1. (CX)-=1
  2. 判断 CX 中的值,如果不为0则转至 label 对应的标号处执行程序,如果为0则向下继续执行

从上面描述中可以看到,CX 寄存器中的值影响着 LOOP 指令的执行结果。通常,使用 LOOP 指令来实现循环功能,CX 中存放循环次数


标号在汇编指令中常常出现在某条语句前,以“ label ”的形式标识某一条语句,代表该地址处有这样一条指令。例如:

sum:
    add ax, bx

标号代表的地址在语句“ ADD AX, BX ”的地址处。

以下是一个利用指令和 CX 寄存器实现的乘方程序,用于计算210

assume cs: codesg
codesg segment
    mov ax, 2
    mov cx, 9
pow:
    add ax, ax
    loop pow

    mov ax, 4c00h
    int 21h
codesg ends
end

该程序一共经历了9次乘方,具体的循环过程分析如下:

  1. 第一次使用 MOV 指令初始化一个2
  2. 每次执行 ADD 指令都相当于进行一次平方运算
  3. CX 寄存器被初始化为9,LOOP 指令每次判断前都使 CX 减少1,只有 (CX) 不为0时才开始循环,这样的循环一共重复8次,再加上最开始进入循环前的一次 ADD 运算,一共进行9次平方运算,所以得到210

从上面的过程中,可以总结出CX寄存器和LOOP指令配合实现循环的要点:

  1. CX 中存放循环次数
  2. LOOP 指令中的标号所标识的地址要在循环开头处
  3. 要循环执行的程序段,应位于标号和 LOOP 指令的中间

CX 寄存器和 LOOP 指令配合实现循环功能的程序框架如下:

    mov cx, loop_times
lopseg:
    ; loop codes
    loop lopseg

段前缀

在汇编源程序中,如果需要用指令访问内存单元,需要在指令中使用“ […] ”来表示一个内存单元。如果在其中使用一个常量“ n ”直接给出内存单元的偏移地址,需要在方括号前面用段寄存器标签如“ DS:[0] ”显式给出段地址所在的段寄存器,否则部分编译器(如masm)会将其直接解释为常量“ n ”。

如果在方括号内使用寄存器 BX 间接给出内存单元的偏移地址,则段地址默认在 DS 中。可以在访问内存单元的指令中显式地给出内存单元所在的段寄存器,例如“ CS: ”、“ SS: ”,称为段前缀。

以下示例程序用来计算FFFF:0~FFFF:F内存单元中存储数据的和:

assume cs: codesg
codesg segment
    mov ax, 0ffffh
    mov ds, ax
    mov bx, 0h  ; initialize DS:BX to ffff:0
    mov cx, 0fh ; loop 15 times
    mov dx, 0h  ; initialize DX = 0 to store the sum
sum:
    mov ax, 0h
    mov al, [bx]
    add dx, ax  ; indirectly add data to DX
    inc bx      ; DS:BX to next memory unit
    loop sum

    mov ax, 4c00h
    int 21h
codesg ends
end

第一,FFFF:0~FFFF:F一共16个单元,每个单元存储的最大数据为255,因此结果 DX 可以存放下。

第二,DX 是16位寄存器,内存单元存放的是8位数据,不能直接相加,只能通过 AX 寄存器间接相加。

第三,使用 LOOP 指令和递增 BX 来遍历内存单元。