[bx+idata]的寻址方式、SI和DI寄存器、[bx+si]和[bx+di]方式寻址、[bx+si+idata]和[bx+di+idata]方式寻址、数据位置的表达、div指令、dup设置内存空间

[bx+idata]的含义解读

[bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata(也就是bx中的数值+idata值)

比如:mov ax,[bx+200],它的含义如下:

1、将一个内存单元的内容关入AX寄存器中

2、这个内存单元的长度为2个字节(字单元),存放一个字

3、内存单元的段地址在ds中,偏移地址为200+bx中存放的数据值

4、数学化的描述为:(ax)=((ds)*16+200+(bx))

mov ax,[bx+200]还有其它写法,如下:

1、mov ax,[200+bx]

2、mov ax,200[bx]

3、mov ax,[bx].200

与C语言中的数组的数据排列有点类似。


SI和DI常执行与地址有关的操作

SI:source index ,源变址寄存器

DI:destination index ,目标变址寄存器

SI和DI是8086CPU中的和BX功能相近的寄存器,前后两者的区别是啥呢?

区别就是SI和DI不能够分成两个8位寄存器来使用。

问题:用寄存 器SI和DI实现将字符串‘welcom to masm’复制到它后面的数据区中。

; ==============================
; 8086汇编 内存块复制程序 - 完整分析版
; 功能:将data段中"welcome to masm!"复制到后续16字节占位区
; 作者:汇编分析
; 日期:2025
; ==============================

; 1. 段关联伪指令:告知编译器段寄存器与段名的对应关系(仅编译提示,无执行逻辑)
assume cs:code,ds:data  

; 2. 数据段定义:存放源字符串和目标占位区
data segment           
    ; 源数据:16字节字符串(w e l c o m e   t o   m a s m !)
    db 'welcome to masm!'  
    ; 目标数据:16字节占位符(初始为点,用于接收复制结果)
    db '................'  
data ends               ; 数据段结束(总长度32字节)

; 3. 代码段定义:存放程序执行逻辑
code segment            
start :                 ; 程序入口标签(end start 指定从此处执行)
    ; --------------------------
    ; 步骤1:初始化DS寄存器,指向data段
    ; --------------------------
    mov ax,data         ; 8086规则:段寄存器不能直接赋值,先将data段地址送入AX
    mov ds,ax           ; 将AX的值送入DS,使DS指向data段(后续[si]/[di]默认用DS段)

    ; --------------------------
    ; 步骤2:初始化循环相关寄存器
    ; --------------------------
    mov si,0            ; SI = 0 → 源数据偏移地址(指向字符串第一个字符'w')
    mov di,16           ; DI = 16 → 目标数据偏移地址(指向占位区第一个点)
    mov cx,8            ; CX = 8 → 循环计数器(每次复制2字节,16字节需8次)

    ; --------------------------
    ; 步骤3:循环复制核心逻辑(2字节/次)
    ; --------------------------
s:                      ; 循环体标签(自定义名称,可替换为任意合法标签)
    mov ax,[si]         ; 取DS:SI指向的2字节数据 → AX(如第一次:偏移0/1的'w'+'e')
    mov [di],ax         ; 将AX中的2字节写入DS:DI指向的地址(第一次:偏移16/17)
    add si,2            ; 源偏移+2 → 指向下一个2字节
    add di,2            ; 目标偏移+2 → 指向下一个2字节
    loop s              ; 循环指令:CX -= 1;若CX≠0则跳回s,否则退出循环

    ; --------------------------
    ; 步骤4:程序正常退出(DOS中断)
    ; --------------------------
    mov ax,4c00h        ; AX = 4C00H → DOS中断功能号(4C=程序退出,00=返回码)
    int 21h             ; 调用21H中断,退出程序返回命令行

code ends               ; 代码段结束
end start               ; 汇编结束指令:1. 标记汇编结束;2. 指定程序入口为start

; ==============================
; 【关键分析】
; ==============================
; 1. 内存布局变化(执行前→执行后):
;    偏移0~15:welcome to masm! → 不变
;    偏移16~31:................ → welcome to masm!
;
; 2. 循环执行过程(8次循环):
;    次数 | CX值 | SI值 | DI值 | 复制的2字节
;    1    | 8    | 0    | 16   | 'w'+'e'
;    2    | 7    | 2    | 18   | 'l'+'c'
;    3    | 6    | 4    | 20   | 'o'+'m'
;    4    | 5    | 6    | 22   | 'e'+' '
;    5    | 4    | 8    | 24   | 't'+'o'
;    6    | 3    | 10   | 26   | ' '+'m'
;    7    | 2    | 12   | 28   | 'a'+'s'
;    8    | 1    | 14   | 30   | 'm'+'!'
;
; 3. 扩展优化(逐字节复制,兼容任意长度):
;    若需复制非2倍数长度的字符串,可修改循环逻辑:
;    mov cx,16          ; 16字节→循环16次
;    s:
;        mov al,[si]    ; 单字节送入AL(代替AX)
;        mov [di],al    ; 单字节写入目标
;        inc si         ; 源偏移+1(代替add si,2)
;        inc di         ; 目标偏移+1(代替add di,2)
;        loop s
;
; 4. 核心知识点:
;    - 段寄存器初始化:DS必须指向数据段,否则内存寻址错误;
;    - loop指令:依赖CX计数器,CX=0时退出循环;
;    - 16位数据传输:AX作为2字节中转寄存器,效率高于单字节(AL);
;    - 物理地址计算:8086物理地址 = 段寄存器值 × 16 + 偏移地址。

[bx+si]和[bx+di]方式寻址

1、偏移地址为(bx)+(si),也就是说用bx中的数值+si中的数值

指令mov ax,[bx+si]的含义解读

1、将一个内存单元的数据或内容送入ax寄存器中

2、这个内存单元的长度为2个字节 

3、偏移地址为bx中的数个+si中的数值

4、段地址默认在ds中

5、mov ax,[bx][si]是另一种写法


[bx+si+idata]和[bx+di+idata]方式寻址

[bx+si+idata]表示一个内存单元,偏移地址为(bx)+(si)+idata,即bx中的数值+si中的数值+idata;

其含义解读与上面的类似


内存寻址方式

寻址方式格式示例寻址逻辑(物理地址计算)适用场景关键说明
[idata]直接寻址MOV AX, [1000H]PA = DS × 16 + 1000H访问固定内存单元(如全局变量)1. 方括号内为16 位偏移量(直接给出有效地址 EA);2. 默认段寄存器为 DS,可显式修改(如MOV AX, ES:[1000H]);3. 偏移量范围:0~FFFFH。
[bx]寄存器间接寻址MOV AX, [BX]PA = DS × 16 + BX(EA=BX)访问数组 / 缓冲区(通过指针)1. 仅允许 BX/SI/DI/BP 作为间址寄存器;2. 用 BP 时默认段寄存器为 SS(栈段),其余默认 DS;3. 无偏移量,纯寄存器存放 EA。
[bx+idata]寄存器相对寻址MOV AX, [BX+100H]PA = DS × 16 + BX + 100H(EA=BX+100H)访问数组元素(基址 + 偏移)1. 格式可简写:[BX+100H]/100H[BX]/[BX]+100H;2. 相对偏移量可为 8 位 / 16 位立即数;3. 间址寄存器仍为 BX/SI/DI/BP。
[bx+si]基址变址寻址MOV AX, [BX+SI]PA = DS × 16 + BX + SI(EA=BX+SI)访问二维数组 / 表格1. 基址寄存器(BX/BP)+ 变址寄存器(SI/DI)组合;2. BP 为基址时默认 SS 段,BX 为基址时默认 DS 段;3. 无额外立即数偏移。
[bx+si+idata]相对基址变址寻址MOV AX, [BX+SI+100H]PA = DS × 16 + BX + SI + 100H访问二维数组(带偏移)1. 基址 + 变址 + 立即数偏移的组合;2. 偏移量可为 8 位 / 16 位;3. 最灵活的寻址方式,覆盖复杂内存访问场景。
隐含寻址(变体)PUSH AX / POP BXPA = SS × 16 + SP(栈操作隐含寻址)栈操作、字符串指令1. 无需显式指定地址,由指令隐含确定;2. 字符串指令(如 MOVSB)隐含用 SI(源)、DI(目的)、DS/ES 段。
串寻址(变体)MOVSB / CMPSB源:DS×16+SI;目的:ES×16+DI字符串批量操作1. 专用字符串指令的寻址方式;2. 执行后 SI/DI 自动 ±1(字节)/±2(字)(由 DF 标志控制)。

问题:编程将每个字母转换为大写字母

;将每个单词的每个字母更改为大写
assume cs:code,ds:data
data segment
		db 'ibm         '
		db 'dec         '
		db 'dos         '
		db 'vax         '
data ends

code segment
		start :
		mov ax,data
		mov ds,ax
		
		mov bx,0
		mov cx,4
		
		s0:mov si,0
		mov cx,3
		s:mov al,[bx+si]
		and al,11011111B
		mov [bx+si],al
		inc si
		loop s
		add bx,16
		loop s0
		
		mov ax,4c00h
		int 21h
code ends
end start

上述代码有个关键错误:内层循环和外层循环共用了 cx 寄存器,导致外层循环的计数被内层循环覆盖,程序逻辑混乱,无法正确执行。

修正代码如下:

增加了一个DX寄存器,做为数据的临时存放,进行中转使用。

但是,修改后的代码有个缺点,就是寄存器未保护:

  • 代码直接修改bx、cx、dx、si、al等寄存器,但未遵循 DOS 汇编的 “寄存器调用约定”(如bx、si、dx属于 “非易失性寄存器”,应先入栈保存,用完恢复)。
  • 若这段代码作为子程序被其他代码调用,会破坏调用方的寄存器值,引发兼容性问题。

再修改完善,如下

assume cs:code,ds:data
data segment
		db 'ibm         '
		db 'dec         '
		db 'dos         '
		db 'vax         '
data ends

code segment
		start :
		mov ax,data
		mov ds,ax
		
		mov bx,0
		mov cx,4
		
	s0:mov ds:[40H],cx
		mov si,0
		mov cx,3
	s:mov al,[bx+si]
		and al,11011111B
		mov [bx+si],al
		inc si
		loop s
		add bx,16
		mov cx,ds:[40H]
		loop s0
		
		mov ax,4c00h
		int 21h
code ends
end start

上述代码,用固定的内存空间保存数据

但是,还是存在问题,比如内存操作原子性缺失:

暂存 / 恢复cx的过程拆分为mov ds:[40H],cxmov cx,ds:[40H]两个独立指令:

  • 若程序被中断(如时钟中断、键盘中断),中断处理程序可能修改ds:[40H]的值,导致恢复cx时拿到错误数值,外层循环次数错乱(如原本循环 4 次,可能变成随机数),程序逻辑完全失控。而上一个版本用dx寄存器暂存,寄存器操作是原子的(不会被中断打断),稳定性远高于内存暂存。

如果结合寄存器的原子性,又能安全地保护数据呢

assume cs:code,ds:data

stack segment
		dw 0,0,0,0,0,0,0,0
stack ends

data segment
		db 'ibm         '
		db 'dec         '
		db 'dos         '
		db 'vax         '
data ends

code segment
		start :
		mov ax,stack
		mov ss,ax
		mov sp,16		
		
		mov ax,data
		mov ds,ax
		
		mov bx,0
		mov cx,4
		
	s0:push,cx
		mov si,0
		mov cx,3
	s:mov al,[bx+si]
		and al,11011111B
		mov [bx+si],al
		inc si
		loop s
		add bx,16
		pop cx
		loop s0
		
		mov ax,4c00h
		int 21h
code ends
end start

核心前提:loop 指令的作用

loop 标号 指令的执行逻辑是:

  1. cx = cx - 1
  2. cx ≠ 0,跳转到标号处;若 cx = 0,执行后续指令。

因此,外层循环的 cx 会从初始的 4,每次循环后减 1,直到变为 0 时退出。

完整执行流程(关键步骤)

    初始:mov cx,4 → cx=4;
    第 1 次执行 s0::
        push cx → 栈中压入4;
        执行内层循环(cx=3),处理第 1 个字符串(ibm→IBM);
        pop cx → 栈中弹出 4,cx 恢复为 4;
        loop s0 → cx=4-1=3,跳回s0;
    第 2 次执行 s0::
        push cx → 栈中压入3;
        执行内层循环(cx=3),处理第 2 个字符串(dec→DEC);
        pop cx → 栈中弹出 3,cx 恢复为 3;
        loop s0 → cx=3-1=2,跳回s0;
    第 3 次执行 s0::
        push cx → 栈中压入2;
        执行内层循环(cx=3),处理第 3 个字符串(dos→DOS);
        pop cx → 栈中弹出 2,cx 恢复为 2;
        loop s0 → cx=2-1=1,跳回s0;
    第 4 次执行 s0::
        push cx → 栈中压入1;
        执行内层循环(cx=3),处理第 4 个字符串(vax→VAX);
        pop cx → 栈中弹出 1,cx 恢复为 1;
        loop s0 → cx=1-1=0,不跳转,退出外层循环。

汇编语言中数据位置的表达

1、立即数2、寄存器内存:段地址(SA)和偏移地址(EA)

对于直接包含在机器指令中的数据,称为立即数idata,数据包含在指令中

mov ax,1

add bx,2000H

or bx,00010000B

mov al,'a'

指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。

mov ax,bx

mov ds,ax

push bx

mov ds:[0],bx

mov ss,ax

mov sp,ax

指令要处理的数据在内存中,由SA:EA确定内存单元。

mov ax,[0]

mov ax,[di]

段地址默认在ds中

mov ax,[bp]

mov ax,[bp+si]

段地址默认在ss中


指令要处理的数据有多长

字word操作字节byte操作用word ptr 或byte ptr 指明数据长度

mov ax,1

mov bx,ds:[0]

mov ds,ax

mov ds:[0],ax

inc ax

add ax,1000

mov al,1

mov al,bl

mov al,ds:[0]

mov ds:[0],al

inc al

add al,100

mov word ptr ds:[0],1

inc word ptr [bx]

inc word ptr ds:[0]

add word ptr [bx],2


div指令

div是除尘指令,使用div做除尘的时候

被除数:(默认)放在AX或DX和AX中

除数:8位或16位,在寄存器或内存单元中

DIV指令格式

div 寄存器 或是 

div 内存单元

被除数AXDX和AX
除数8位内存或寄存器16位内存或寄存器
ALAX
余数AHDX

dup功能和用法

dup和db、dw、dd等数据定义伪指令配合使用,用来进行数据的重复

指令功能相当于
db 3 dup(0)定义了3个字节,它们的值都是0db 0,0,0
db 3 dup(0,1,2)定义了9个字节,由0,1,2重复3次构成db 0,1,2,0,1,2,0,1,2
db 3 dup('abc','ABC')定义了18个字节,构成‘abcABCabcABCabcABC’db 'abcABCabcABCabcABC'

posted @ 2025-12-06 11:55  chenlight  阅读(8)  评论(0)    收藏  举报  来源