6.1 数据传送指令
第 5 章介绍了指令字节怎样指定操作数。现在继续追问:处理器完成译码后,机器状态究竟发生什么变化?数据传送指令用于复制、交换、装入或保存位模式。“传送”并不表示源数据消失;处理器通常读取源,再把相同副本写入目的。
MOV:复制但不清空源
MOV 目的,源 复制一个字节或一个字。两个操作数的宽度必须相同,因此 MOV AX,BL 非法:AX 是 16 位,BL 是 8 位。
8086 的普通 MOV 支持寄存器到寄存器、立即数到寄存器或存储器、寄存器到存储器,以及存储器到寄存器。它不支持通用的存储器到存储器形式,因为编码中最多只能容纳一个普通存储器操作数。程序必须使用寄存器中转:
MOV AX,[1000H]
MOV [1002H],AX取指本身也会访问存储器,但这里所说的操作数总线周期,是数据操作数额外需要的读或写。MOV AX,BX 不需要操作数存储器周期;MOV AX,[1000H] 需要一次读;MOV [1000H],AX 需要一次写。
MOV、XCHG、LEA、PUSH 和 POP 都不修改算术状态标志。因此程序可以移动数据,而不会破坏稍后条件跳转所需的比较结果。
XCHG 与 LEA 解决不同问题
XCHG 左操作数,右操作数 交换两个操作数。内部临时值保证两个原值都不会丢失。至少一个操作数必须是寄存器,不能同时使用两个存储器操作数。
LEA 寄存器,存储器表达式 表示装入有效地址(load effective address)。它计算存储器表达式描述的偏移量,并把这个数写入寄存器,但不会读取该偏移量处的内存数据。
假设 BX=1000H、SI=0020H,偏移量 1024H 处保存 BEEFH:
MOV AX,[BX+SI+4]读取存储器,得到 AX=BEEFH。
LEA AX,[BX+SI+4]只做地址计算,得到 AX=1024H。
当程序需要的是指针而不是指针指向的数据时,这个区别非常重要。
PUSH 与 POP 通过栈传送字
8086 的栈(stack)是使用 SS:SP 寻址的后进先出区域。字 PUSH 先让 SP 减 2,再把字写入新的 SS:SP;POP 先读取 SS:SP 处的字,再让 SP 加 2。
若 SP 初值为 0100H,AX 保存 1234H,PUSH AX 会把 SP 改为 00FEH。小端存储使 34H 位于 SS:00FEH,12H 位于 SS:00FFH。随后 POP BX 在 BX 中重建 1234H,并把 SP 恢复为 0100H。
不要从程序此前未建立的栈位置弹出数据。PUSH 与 POP 数量不匹配会改变 SP,并可能使后续过程返回读取错误地址。
现在你已经能判断数据从哪里来、到哪里去,以及是否访问存储器。第 6.2 节将加入算术:目的操作数仍会改变,但标志位还会记录结果的性质。