汇编中[...]与(...)的规定,loop指令及其应用

[......]     在汇编语法的规则 中,这表示一个内存单元

指令 段地址偏移地址   操作单位
mov ax,[0]在DS中在[0]中
mov al,[0]在DS中在[0]中字节
mov ax,[bx]在DS中在[bx]中
mov al,[bx]在DS中在[bx]中字节

(......)   这是为学习方便做出的约定 ,表示一个内存单元或寄存中的内容 

描述对象描述方法描述对象描述方法
ax中的内容为0010H(ax)=0010H2000:1000处的内容为0010H(21000H)=0010H
mov ax,[2]的功能(ax)=((ds)*16+2)mov [2],ax的功能((ds)*16+2)=(ax)
add ax,2的功能(ax)=(ax)+2add ax,bx的功能 (ax)=(ax)+(bx)
push ax的功能

(sp)=(sp)-2

((ss)*16+(sp))=(ax)

pop ax的功能

(ax)=((ss)*16+(sp))

(sp)=(sp)+2

Loop指令

1、功能:实现循环(计数型循环)

2、指令格式:loop + 标号

; 功能:计算 1+2+...+10,结果存AX寄存器
MOV CX, 10         ; 1. 初始化循环次数=10(CX=10,循环10次)
MOV AX, 0          ; 2. 结果寄存器AX清零(用于存累加和)
SUM_LOOP:          ; 3. 循环标签(loop跳转目标)
    ADD AX, CX     ; 4. 循环体:AX = AX + CX(第一次加10,第二次加9...)
LOOP SUM_LOOP      ; 5. loop核心:CX -= 1;若CX≠0,跳回SUM_LOOP;CX=0则退出
; 执行后:AX=55(1+2+...+10的结果)

3、cpu执行loop指令的时候要进行的操作,如下

3.1 (cx)=(cx)-1;

3.2 判断cx中的值

        不为0,则转至标号处执行程序

        如果为0,则跳出循环,向下执行;

下面看一个具体的实例

CX:计数寄存器

loop每循环一次,CX的值就会减1


在debug中,mov al,[0]的功能是:

将DS:0存储单元的值传给AL


访问连续的内存单元---loop和[BX]联手

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

代码解读:

assume cs:code  ; 伪指令:假设代码段寄存器cs指向code段(仅编译提示,无执行逻辑)
code segment    ; 定义代码段开始
        mov ax,0ffffH  ; 将立即数0FFFFH送入ax(8086不能直接给段寄存器赋值,需通过通用寄存器中转)
        mov ds,ax      ; 将ax的值(0FFFFH)送入数据段寄存器ds,此时ds=0FFFFH(数据段基址)
        
        mov bx,0       ; bx=0(作为内存偏移地址,初始指向ds:0,即0FFFF:0000H)
        mov dx,0       ; dx=0(累加器初始化,用于存储12个字节的累加和)
        mov cx,12      ; cx=12(loop循环计数器,控制循环执行12次)
        
        ; 循环体开始(标签s)
        s:mov al,[bx]  ; 读取ds:bx(0FFFF:bx)地址处的1个字节,送入al(8位寄存器)
           mov ah,0    ; ah=0(将al的8位数值扩展为ax的16位数值,避免累加时高位干扰)
           add dx,ax   ; 将ax(扩展后的字节值)加到dx中(dx = dx + ax)
           inc bx      ; bx自增1(偏移地址+1,指向下一个字节)
           loop s      ; cx自减1,若cx≠0则跳回标签s继续循环;直到cx=0退出循环
        
        mov ax,4c00h  ; ax=4C00H(DOS中断功能号:程序正常退出)
        int 21h       ; 调用DOS 21H中断,执行程序退出操作
code ends       ; 代码段结束
end             ; 汇编程序结束(指定程序入口,此处默认从代码段起始处执行)

段前缀的使用

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

ffff:00020:0
ffff:10020:1
ffff:20020:2
ffff:30020:3
ffff:40020:4
ffff:50020:5
ffff:60020:6
ffff:70020:7
ffff:80020:8
ffff:90020:9
ffff:a0020:a
ffff:b0020:b

assume cs:code  ; 伪指令:声明cs寄存器关联code段(仅编译提示,无执行逻辑)
code segment    ; 定义代码段开始
        mov bx,0       ; bx=0(偏移地址初始化,同时作为源/目标地址的偏移量,初始指向0号偏移)
        mov cx,12      ; cx=12(loop循环计数器,控制拷贝12个字节)
        
        ; 循环体开始(标签s)
        s:mov ax,0ffffh  ; ax=0FFFFH(给数据段寄存器ds赋值的中转,8086不支持直接给ds赋值)
           mov ds,ax      ; ds=0FFFFH(将ds指向源数据段:0FFFFH段)
           mov dl,[bx]    ; 读取源地址 ds:bx(0FFFF:bx)的1个字节,存入dl(8位寄存器,临时存储)
           
           mov ax,0020h   ; ax=0020H(中转赋值)
           mov ds,ax      ; ds=0020H(将ds指向目标数据段:0020H段)
           mov [bx],dl    ; 将dl中临时存储的字节,写入目标地址 ds:bx(0020:bx)
           
           inc bx         ; bx自增1(偏移地址+1,指向下一个字节)
           loop s         ; cx自减1,若cx≠0则跳回s继续循环;cx=0时退出循环
        
        mov ax,4c00h  ; ax=4C00H(DOS中断功能号:程序正常退出)
        int 21h       ; 调用DOS 21H中断,执行退出操作
code ends       ; 代码段结束
end             ; 汇编程序结束(入口默认是代码段起始处)

通过分离ds(源段)和es(目标段),避免循环内反复切换数据段,是 8086 汇编中内存拷贝的「优化写法」,如下

代码解读;

assume cs:code
code segment
        ; 1. 初始化源段寄存器ds、目标段寄存器es(仅执行1次,而非循环内反复执行)
        mov ax,0ffffh  
        mov ds,ax      ; ds = 0FFFFH(源数据段:0FFFF0H + bx)
        mov ax,0020h   
        mov es,ax      ; es = 0020H(目标附加段:00200H + bx)
        
        ; 2. 初始化偏移地址和循环计数器
        mov bx,0       ; bx = 0(源/目标地址的偏移量,初始指向0号偏移)
        mov cx,12      ; cx = 12(控制循环执行12次)
        
        ; 3. 循环拷贝(核心优化:无需切换段寄存器)
        s:mov dl,[bx]       ; 读取源地址 ds:bx → dl(8位临时存储)
           mov es:[bx],dl   ; 写入目标地址 es:bx ← dl(直接用es指定目标段)
           
           inc bx           ; 偏移地址+1,指向下一个字节
           loop s           ; cx-1,非0则跳回s
        
        ; 4. 程序退出
        mov ax,4c00h  
        int 21h       
code ends
end

es(Extra Segment)是 8086 的附加段寄存器,专门用于「数据读写的辅助段寻址」,常见于:

  1. 内存拷贝 / 数据块移动(分离源段ds和目标段es);
  2. 字符串操作指令(如movsbstosb)的默认目标段;
  3. 避免反复切换ds导致的效率损耗。

本代码中 mov es:[bx],dl 是「显式段超越前缀」写法 —— 明确指定用es作为段寄存器,而非默认的ds,这是 8086 汇编的标准写法。


DW:define word 定义字型数据

在8086CPU中,字型大小为16位

类似有的还有:

dw 定义一个字

db 定义一个字节

dd 定义一个双字

问题:下面使用dw编程计算8个数据的和,结果存放在ax寄存器中

代码解读

assume cs:code
code segment
    ; 在CS寄存器中定义8个16位字数据(dw=define word,每个占2字节,共16字节)
    dw 0123H, 0456H, 0789H, 0ABCH, 0DEFH, 0FEDH, 0CBAH, 0987H  

start:  ; 显式指定程序入口(避免CPU执行数据区)
    mov bx, 0       ; bx=0(偏移地址,指向第一个字数据)
    mov ax, 0       ; ax=0(累加器,初始化累加和)
    mov cx, 8       ; cx=8(循环计数器,匹配8个数据,无越界)
    
    ; 循环累加:每次取1个16位字,偏移+2
    s: add ax, cs:[bx]  ; ax = ax + 代码段中bx偏移的16位数据
       add bx, 2        ; bx+2(指向下一个16位字)
       loop s           ; cx-1,非0则跳回s
    
    ; DOS中断退出程序
    mov ax, 4c00h
    int 21h
code ends
end start  ; 指定程序入口为start标签(核心修正)

数据存储如下

23CS:0数据区
01CS:1
56CS:2
04CS:3
89CS:4
07CS:5
BCCS:6
0ACS:7
EFCS:8
0DCS:9
EDCS:A
0FCS:B
BACS:C
0CCS:D
87CS:E
09CS:F
CS:10代码区
CS:11
CS:12
CS:13
CS:14
CS:15

posted @ 2025-12-04 11:00  chenlight  阅读(3)  评论(0)    收藏  举报  来源