技术

ICS 与 8086 复习 06:8086 寻址与数据传送

ICS 与 8086 汇编复习 · 第 06 篇 系列目录 · 上一篇 · 下一篇

2000H 可能是一个数,也可能是偏移地址,还可能是段寄存器的内容。读汇编程序时,先弄清它在当前指令中的身份,才能正确计算结果。8086 的寻址题看似形式很多,实际可以沿着同一条路径求解:确定操作数在哪里,算出有效地址,再按操作宽度读取数据。

本文采用 8086 实模式与 Intel/MASM 语法,双操作数指令的目的在前、源在后。复习时优先掌握寻址合法性、默认段、大小端和栈的变化;它们也会反复出现在后续的程序分析题中。

先判断是数值还是内存内容

比较下面三条指令:

mov ax, 1234h
mov ax, [1234h]
mov ax, bx

第一条把立即数 1234H 送入 AX。第二条访问默认数据段内偏移为 1234H 的一个字,把其中内容送入 AX。第三条直接复制 BX 的值。

因此,看到方括号时,应先想到“按这个地址访问内存”。但 MASM 的符号变量有类型,若 value DW 1234H,mov ax,value 同样表示读取内存;它与 mov ax,OFFSET value 的含义不同,后者取得的是变量的偏移地址。

寻址方式要针对具体操作数判断。mov ax,1234h 的源是立即寻址,目的仍是寄存器寻址,不能把整条指令简单标成只有一种寻址方式。

有效地址和物理地址分两步计算

有效地址 EA 是段内偏移。8086 实模式下,在本篇未跨越地址空间上界的例子中,物理地址为:

PA = 段寄存器值 × 10H + EA

注意 10H 是十进制的 16。段值左移四位后再加偏移,不能直接把两个十六进制数相加。

8086 数据寻址可以整理成下表。

形式 示例 EA 的来源
直接寻址 [2000H] 指令中的偏移量
寄存器间接 [BX] 一个地址寄存器
寄存器相对 [SI+10H] 地址寄存器加位移
基址变址 [BX+DI] 一个基址加一个变址
相对基址变址 [BP+SI+10H] 基址、变址与位移相加

这里有两个必须记牢的限制。第一,8086 的一般内存有效地址只能使用 BX、BP、SI、DI,不能写 [AX]、[CX]、[DX] 或 [SP]。第二,双寄存器组合只能从 BX/BP 中选一个、从 SI/DI 中选一个,所以 [BX+BP]、[SI+DI] 都不合法。

默认段同样有规律:一般数据访问使用 DS;有效地址包含 BP 时使用 SS。显式的段超越前缀可以改用指定的段,例如 mov ax,DS:[BP]。

这是一般数据访问的规则。取指使用 CS:IP,压栈弹栈使用 SS:SP,串指令又有专门的隐含地址约定,不能只凭出现了 DI 就一律认定使用 DS。

一道寻址题的完整解法

已知:

SS=3000H,DS=2000H
BP=0100H,SI=0020H
物理地址30130H处的字节是34H
物理地址30131H处的字节是12H

执行:

mov ax, [bp+si+10h]

第一步计算偏移:EA=0100H+0020H+0010H=0130H。

第二步选择段。因为地址表达式包含 BP,默认使用 SS,因此 PA=3000H×10H+0130H=30130H。

第三步确定宽度。目的操作数 AX 是 16 位寄存器,所以读取从该地址开始的两个字节。

第四步按小端顺序组合:低地址的 34H 是低字节,后一地址的 12H 是高字节,最终 AX=1234H。BP、SI 以及被读取的内存都没有因此改变。

这四步可以直接用作答题模板。尤其不要把 EA=0130H 当作 AX 的结果,也不要因为 DS 已知就跳过默认段的判断。

MOV 的合法性和 LEA 的区别

普通 MOV 不影响条件标志,源数据也不会因为“传送”而被清除。判断是否合法时,依次检查以下几项:

  • 两边宽度是否匹配,例如 mov al,ax 不合法。
  • 是否同时访问两个内存操作数,普通 MOV 不支持这种形式。
  • 是否试图把立即数直接送入段寄存器,或在两个段寄存器间直接传送。
  • 目的是否是立即数、CS 或 IP;这些都不能作为普通 MOV 的目的。

装载数据段可以写为:

mov ax, 2000h
mov ds, ax

mov ds,2000h 不能替代这两条指令。

对于只有内存和立即数、无法推断宽度的指令,要用 PTR 明确类型:

mov byte ptr [bx], 1
mov word ptr [bx], 1

前者改一个字节,后者改两个字节。PTR 规定本次访问的宽度,不会重新定义整片内存的永久类型。

LEA 则只计算有效地址,不读取该地址中的数据:

lea ax, [bx+si+10h]

若 BX 为 0100H、SI 为 0020H,结果就是 AX=0130H,不会再取 DS:0130H 处的一个字。LDS、LES 又不同:它们从内存读取一个由偏移和段值组成的远指针,同时装载通用寄存器与 DS 或 ES。

栈题抓住操作顺序

8086 的栈以字为单位操作。执行普通 PUSH 时,先把 SP 减 2,再向 SS:SP 指向的位置写入一个字;POP 先读取栈顶字,再把 SP 加 2。

设 AX=1234H、BX=ABCDH、SP=0100H,执行:

push ax
push bx
pop cx
pop dx
执行后 SP 关键结果
push ax 00FEH 栈顶字为 1234H
push bx 00FCH 新栈顶字为 ABCDH
pop cx 00FEH CX=ABCDH
pop dx 0100H DX=1234H

第二次压栈后,偏移 00FCH、00FDH 两字节分别为 CDH、ABH。这同时体现了栈向低地址增长和字数据的小端存储。

POP 不会把原内存擦成零,只会读出数据并移动栈顶。保存 AX、BX、CX 后,恢复顺序通常应为 CX、BX、AX。普通 PUSH、POP 不改条件标志;专门恢复标志的 POPF 另当别论。

8086 不支持 push al 或 push 1234h。后代 x86 增加的指令形式,不能直接搬进限定为 8086 的改错题。

常见误区

把 mov ax,[bx] 误读成复制 BX,会把地址和内容混淆;把 LEA 误读成 MOV,则会多做一次内存读取。计算物理地址时漏乘 16、含 BP 仍使用 DS、按高地址先拼字,也都会让后续结果整体出错。

另一个跨课程陷阱是套用 386 的比例变址。[EAX+ESI*4] 是后续 IA-32 内容;8086 的地址寄存器和可用组合应按本篇限制单独记忆。

自测与答案

  1. 已知 DS=1000H、BX=0020H,物理地址 10020H、10021H 分别存 78H、56H。mov ax,[bx] 后 AX 是多少?lea ax,[bx] 呢?
  2. [BP+DI+8]、[BX+BP]、[SP] 在 8086 中哪些合法?合法者默认使用哪个段?
  3. 初始 SP=0200H,依次执行 push ax、push bx、pop cx 后,SP 是多少?CX 来自哪个寄存器原值?

答案:1. 前者为 5678H,后者为 0020H。2. 只有 [BP+DI+8] 合法,默认使用 SS;另外两种无对应的 8086 一般寻址形式。3. SP=01FEH,CX 得到 BX 压栈时的值。

对应课件

《汇编语言 第3章.pptx》:第 7—33 页寻址方式,第 47—61 页 MOV 与栈,第 66—68 页 LEA、LDS、LES。页码按文件中的幻灯片顺序计。

系列导航

CONTINUE / PATH

从这里继续

顺着当前内容继续,或者换到另一个板块。

讨论这篇文章

关于《ICS 与 8086 复习 06:8086 寻址与数据传送》的补充、不同意见或延伸话题,都可以留在这里。

滚动到这里时自动载入留言。