ICS 与 8086 复习 05:8086 寄存器与分段寻址
看到 1234:0010,先不要把它当成一个普通的十六进制数。冒号左边是段值,右边是偏移量,两者共同定位内存。8086 地址题的关键,是把寄存器、逻辑地址、物理地址和内存内容分开计算。
本篇复习目标:会认寄存器,会算段地址,会按小端顺序读写字数据,并能解释为什么不同逻辑地址可以指向同一字节。
先画清寄存器的分工
8086 的主要程序可见寄存器都是 16 位。按用途记,比逐个背英文缩写更有效。
| 类别 | 寄存器 | 做题时首先想到的用途 |
|---|---|---|
| 数据寄存器 | AX、BX、CX、DX | 保存数据;部分指令有隐含操作数 |
| 指针与变址寄存器 | SP、BP、SI、DI | 栈顶、栈中数据、源与目标地址 |
| 段寄存器 | CS、DS、SS、ES | 提供代码、数据、栈、附加段的段值 |
| 指令指针 | IP | 与 CS 配合确定指令位置 |
| 标志寄存器 | FLAGS | 记录运算状态并控制部分执行行为 |
AX 可拆成 AH 和 AL,BX、CX、DX 同理。若 AX=1234H,则 AH=12H、AL=34H。随后执行 MOV AL,56H,AX 成为 1256H,AH 没有改变。SI、DI、BP、SP 在 8086 中不能这样拆成高低字节寄存器。
还要记住三组常见的隐含关系:LOOP 使用 CX;串指令常使用 SI、DI、CX;字乘除常涉及 AX 或 DX:AX。CX 与 CL 是同一个寄存器的整体和低字节,不能把二者当作互不影响的两个计数器。
16 位寄存器如何找到 1 MiB 内存
8086 有 20 根地址线,物理地址范围为 00000H 到 FFFFFH,共 2^20 个字节,即 1 MiB。单个 16 位值只有 0000H 到 FFFFH,因此采用段值与偏移量共同形成地址:
段基址 = 段值 × 10H
物理地址 = 段基址 + 偏移量
这里的 10H 等于十进制 16。段寄存器存放的是段值,左移四位后才得到段基址。例如 DS 为 1234H,对应段基址是 12340H,不能直接把 1234H 加到偏移量上。
16 位偏移量使一个段能够表示的偏移范围为 0000H 到 FFFFH,覆盖最多 64 KiB。段基址按 16 字节对齐;这不代表段的长度只有 16 字节,也不代表各段必须互不重叠。
以下例子都不跨越 1 MiB 边界。对原始 8086,若加法产生第 21 位,地址总线上只留下低 20 位,不能把这种边界行为直接推广到所有后续 x86 环境。
一道地址题,分四步计算
已知:
DS = 1234H SS = 2000H
BX = 0010H SI = 0004H BP = 0010H
求 MOV AX,[BX+SI+6] 所访问的地址,并求执行结果。这里未带后缀的 6 按通常 MASM 默认十进制理解,恰好与 6H 相同。
- 先算有效地址:
0010H+0004H+0006H=001AH。 - 该地址表达式不含 BP,默认使用 DS。
- 算物理地址:
1234H×10H+001AH=1235AH。 - MOV 的目标是 AX,因此读取连续两个字节,而不是只读一个字节。
若物理地址 1235AH 的内容为 78H,1235BH 的内容为 56H,则 AX=5678H。低地址保存低字节,这是 x86 的小端存储顺序。
换成 MOV AX,[BP+6],有效地址为 0016H,但默认段改为 SS,所以物理地址是 20016H。同样的偏移量,搭配不同段寄存器,就可能访问完全不同的位置。
默认段和合法寻址组合
常见的默认配对如下。
| 场景 | 默认地址关系 |
|---|---|
| 取指令 | CS:IP |
| 普通数据访问,地址表达式不含 BP | 通常使用 DS |
| 普通数据访问,地址表达式含 BP | 通常使用 SS |
| PUSH、POP 等栈操作 | SS:SP |
| MOVSB 等串传送的源与目标 | DS:SI 与 ES:DI |
8086 中,普通内存操作数可用 BX、BP、SI、DI 构造地址。常见合法双寄存器组合是 [BX+SI]、[BX+DI]、[BP+SI]、[BP+DI],并可再加位移量。[AX]、[SP]、[BX+BP]、[SI+DI] 不能直接套用为 8086 的普通有效地址形式。
段超越前缀可以改变许多普通数据访问的默认段,但不能因此认为每一种隐含访问都能任意换段。尤其要单独记住串指令的目的地址 ES:DI。
地址不唯一,内存字节却是同一个
比较以下两个逻辑地址:
1234:0010 → 12340H + 0010H = 12350H
1235:0000 → 12350H + 0000H = 12350H
它们对应同一物理地址。因此,“段地址不同”不能推出“物理地址不同”。判断是否重合必须代入公式,不能只比较冒号左边。
栈题也遵循相同规则。若 SS=2000H、SP=0100H、AX=1234H,执行 PUSH AX 后,SP 先减 2,成为 00FEH,随后把 34H 写到 200FEH、12H 写到 200FFH。栈向低地址增长与字内的小端顺序,是两个需要同时应用的规则。
读寄存器值与读内存值是两次不同的动作
比较 MOV AX,BX 与 MOV AX,[BX]。前者复制 BX 中的数值,后者把 BX 当作偏移量,使用默认数据段访问内存,再把读到的字放入 AX。假如 BX 为 0010H,前者的结果已经确定;后者的结果还依赖 DS,以及相应两个字节的内存内容。
因此,求程序运行结果时不能停在“算出了物理地址”。地址只是找到了门牌,最后还要根据访问宽度、字节顺序和内存初值求出实际操作数。反过来,若题目只给寄存器而没有给内存内容,就可能只能算出地址,不能凭空写出 AX 的最终值。
检查题目条件也能减少无效计算:读 AL 只需一个字节,读 AX 要两个字节;立即数操作不需要访问该数值所对应的内存地址;寄存器间复制也不需要拿段值参与运算。
标志判断必须带着位宽与数值解释
FLAGS 并不把每个结果简单归类为“对”或“错”。例如 8 位加法 7FH+01H 得到 80H:按无符号数解释,127 加 1 仍在范围内,CF=0;按带符号数解释,两个正数得到负数编码,OF=1。SF=1 只说明结果最高位为 1,不能单独证明有符号计算没有溢出。
做标志题时,先标出操作数是字节还是字,再按该位宽计算保留结果。不要因为纸面上写了四位十六进制,就把字节指令擅自当成字指令。具体判定方法见第07篇。
易错点
- 段值、段基址、偏移量和存储内容是四种不同的量,答题时最好分别写出。
DS=1234H表示段值,不表示内存1234H地址中的内容。- 同一逻辑地址在给定环境中确定一个物理地址;同一物理地址通常可用多个逻辑地址表示。
- FLAGS 中 ZF=1 表示结果为零;PF 只统计结果最低字节中 1 的个数;CF 与 OF 分别服务于不同的数值解释。
- 原课件第2章第22页把 BX 与 AX、CX、DX 一并排除在地址寄存器之外,这是笔误;BX 是 8086 合法的基址寄存器。课件后面出现的 FS、GS 属于后续处理器,8086 只有 CS、DS、SS、ES 四个段寄存器。
三道自测
题 1。 DS=1000H,BX=0020H,执行 MOV AL,[BX+3],物理地址是多少?
答: 默认使用 DS,有效地址为 0023H,物理地址为 10023H;因为目标是 AL,所以读一个字节。
题 2。 2000:0010 与 2001:0000 是否相同?
答: 二者的物理地址都是 20010H,对应同一字节。
题 3。 地址 30000H、30001H 依次存放 CDH、ABH,读取该处的字得到什么?
答: 得到 ABCDH。若仅读取第一个字节,则得到 CDH。
对应课件
《汇编语言 第2章.ppt》第5—18页:字节、字、小端存储与逻辑地址;第19—26页:寄存器分类;第27—35页:标志;第37—40页:段寄存器与默认配对。寄存器代际对照见第44—46页。《汇编语言 第3章.pptx》第18—28页:合法有效地址组合、默认段和段超越。本文计算题为据上述原理重新编写的复习例题。
讨论这篇文章
关于《ICS 与 8086 复习 05:8086 寄存器与分段寻址》的补充、不同意见或延伸话题,都可以留在这里。
滚动到这里时自动载入留言。