5.4 有效地址与段选择规则
5.3 节计算出了 16 位有效地址,但它还不是 8086 放到总线上的物理地址。BIU 必须把 EA 与一个段寄存器配对:
指令通常不写出段名,因为 8086 会应用默认规则。
核心默认规则
对于本章介绍的普通存储器地址表达式:
- 有效地址计算中包含 BP 时,使用 SS;
- 否则使用 DS。
因此:
| 操作数 | 默认段 | 原因 |
|---|---|---|
[BX+SI] | DS | 不含 BP |
[SI+10H] | DS | 不含 BP |
[BP] | SS | BP 参与计算 |
[BP+DI+08H] | SS | BP 参与计算 |
[1234H] | DS | 直接数据偏移量 |
该规则检查的是哪个寄存器参与了编码的有效地址,而不是程序员是否在概念上把这份数据称为“栈数据”。
其他指令类别有各自固定或常用的段行为。取指使用 CS:IP,栈操作使用 SS:SP,串操作源通常使用 DS:SI,串操作目的使用 ES:DI。应把每种特殊指令与自身段规则一起学习,不要强行让所有情况都套用普通 BP 判断。
段超越会替换默认段
段超越前缀(segment-override prefix)为一个存储器操作数显式指定 CS、DS、SS 或 ES。例如:
MOV AX,DS:[BP+SI]有效地址仍然是 BP+SI;改变的只是段来源由默认 SS 变成 DS。前缀会增加一个指令字节,因此它应当表达真实寻址需求,而不是机械添加。
实验 1——预测并覆盖所选段
选择存储器表达式与可选前缀。路由器会把默认判断、实际选择的段、EA 和最终物理地址显示为一条完整因果路径。
检查理解
相同 EA 可以到达不同物理存储器
假设:
那么:
偏移量完全相同,但物理地址相差 10000H。若 20120H 保存 CAFEH,30120H 保存 BEEFH,那么未加段超越的 [BP+SI] 会读取 BEEFH,因为 BP 选择默认 SS。
这会形成一种常见调试模式:
1. 寄存器算术看起来正确。
2. EA 是预期数值。
3. 返回的数据却不正确。
4. 实际故障在于选错了段。
与第 4 章介绍的原始 8086 一样,如果加法产生额外一位,只有低 20 位会到达 A19…A0 引脚。
实验 2——诊断“EA 正确但数据错误”的故障
四个段在相同 EA 保存不同测试字。根据需要保留或更换地址表达式、应用段超越、发起读取,并比较实际物理地址和返回值。
检查理解
完整存储器操作数算法
看到一个 8086 存储器操作数时:
1. 译码 mod 与 r/m,确定合法地址寄存器和位移。
2. 计算 EA,并保留低 16 位。
3. 选择默认段:普通 BP 基址地址使用 SS,否则使用 DS。
4. 若存在合法段超越前缀,就用它替换默认段。
5. 把选定段值左移四位,再加 EA。
6. 使用得到的 20 位总线地址读写操作数字节。
至此,我们完成了从机器码字段到物理存储器事务的连接。第 6 章可以在这些规则之上继续学习数据传送、算术、逻辑、移位、比较、分支、循环和串指令。