计组与微机控制
7.1 x86寻址方式
7.1 x86寻址方式
8086/8088 寻址方式:从这里开始是重点中的重点。
寻址方式讲的是:指令如何找到操作数
一条指令里面可能直接给数据,也可能给地址,也可能让 CPU 用寄存器算地址。
一、操作数的种类
课本把操作数分成两大类:数据操作数 转移地址操作数
1. 数据操作数数据操作数就是参与数据运算或传送的数据。
它可以分为:立即数操作数 寄存器操作数 存储器操作数 I/O 操作数
例如:MOV AX, 1234H 1234H 是立即数操作数。
MOV AX, BX BX 是寄存器操作数。
MOV AX, [1000H] [1000H] 是存储器操作数。
IN AL, 60H 60H 是 I/O 端口操作数。
2. 转移地址操作数
转移地址操作数用于跳转、调用等指令。比如:
JMP 2000H CALL SUB1
这里操作数不是普通数据,而是程序要跳到的目标地址。
课本说转移地址也可以在:
指令中 寄存器中 存储器中
后面讲 JMP、CALL 时会用到。
二、寻址方式分两大类
8086/8088 寻址方式分为:数据寻址方式 转移地址寻址方式
现在课本先讲数据寻址方式。
数据寻址方式 1:立即寻址
立即寻址就是操作数直接写在指令中。例如: MOV AX, 1234H
这里:1234H 直接跟在操作码后面
CPU 执行时不用去内存里找这个数据,因为数据本身就在指令代码里。
1. 立即数只能作源操作数
立即寻址通常用来给寄存器或存储器赋初值。
例如: MOV AX, 1234H MOV AL, 20H ADD AX, 1
但是不能写:MOV 1234H, AX 因为立即数是常数,不能作为目的操作数。
2. 立即数在机器码中的存放
比如:MOV AX, 1234H 在机器码中,立即数 1234H 会按小端存放:34H 12H
因为低字节在前,高字节在后。
三、数据寻址方式 2:寄存器寻址
寄存器寻址就是操作数在寄存器中。例如:MOV CL, DL
意思是:把 DL 的内容送到 CL
因为 CL 和 DL 都是 CPU 内部寄存器,所以速度很快。
1. 16 位寄存器 16 位操作数可以用:
AX、BX、CX、DX、SI、DI、SP、BP
例如:MOV AX, BX ADD CX, DX
2. 8 位寄存器 8 位操作数可以用:
AL、AH、BL、BH、CL、CH、DL、DH
例如:MOV AL, BL MOV CL, DL
3. 寄存器寻址速度快
因为数据就在 CPU 内部,不需要通过总线访问内存。
所以寄存器寻址通常比存储器寻址快。
这就是为什么汇编程序中经常先把内存数据取到寄存器,再在寄存器里运算。
四、数据寻址方式:存储器寻址
存储器寻址就是操作数在内存中。指令要通过某种方式给出有效地址 EA。
CPU 根据 EA 和段寄存器得到物理地址,再访问内存。
存储器寻址下面又分很多种。存储器寻址一定带 [ ]
比如:MOV AX, [1000H] MOV AX, [SI] MOV AX, [BX+DI] MOV AX, [BP+DI+20H]
方括号表示:不是取这个寄存器本身,而是取它所指向内存地址里的内容(之前RTL语句就是这种作用,也就是间接寻址,之前都讲过)
存储器寻址 1:直接寻址
直接寻址就是指令中直接给出偏移地址。例如:MOV AX, [1000H]
这里有效地址:EA = 1000H默认段寄存器是 DS。
所以物理地址是:DS × 10H + 1000H
这条指令的意思是:从 DS 段中偏移地址 1000H 开始,取一个字送入 AX
因为 AX 是 16 位,所以要取两个字节:DS:1000H → AL DS:1001H → AH
注意还是小端:低地址内容进入 AL,高地址内容进入 AH。
图中类似:DS = 2000H 偏移 = 1000H

物理地址:2000H × 10H + 1000H = 21000H
如果:21000H = 78H 21001H = 56H
那么:AL = 78H AH = 56H AX = 5678H 这就是小端存放。
2. 段超越 默认直接寻址用 DS。
如果想用 ES:MOV AX, ES:[2000H]
意思是:从 ES 段中偏移地址 2000H 处取一个字送入 AX
物理地址是:ES × 10H + 2000H这就是段超越。
3. 符号地址
汇编里也可以用变量名。例如:TABLE DB 30H MOV BL, [TABLE]
意思是:把 TABLE 所在内存单元中的 30H 送入 BL
课本里还写了类似:MOV BX, TABLE
作为常用形式。不同汇编器对是否需要方括号、是否表示 OFFSET 会有差异。
先理解为:TABLE 是变量名,代表某个内存地址访问 TABLE 就是访问这个地址处的数据
后面真正写 MASM/TASM 时,我们再专门区分 TABLE、[TABLE]、OFFSET TABLE。
2:寄存器间接寻址
寄存器间接寻址就是:有效地址 EA 放在寄存器里
常用形式:MOV AX, [SI] MOV AX, [DI] MOV AX, [BX] MOV AX, [BP]
1. [SI] 的意思MOV AX, [SI]
不是把 SI 的值送到 AX。
而是:把 SI 作为偏移地址 到内存中取一个字 送入 AX
默认段寄存器:SI、DI、BX 默认用 DS BP 默认用 SS
所以:MOV AX, [SI]默认是:
MOV AX, DS:[SI]
2. 图 4.4 中类似:
DS = 3000H SI = 2000H
物理地址:3000H × 10H + 2000H = 32000H
如果内存中:32000H = 56H 32001H = 34H
那么:AL = 56H AH = 34H AX = 3456H
所以:MOV AX, [SI] 执行后: AX = 3456H
3. 为什么叫“间接”?
因为指令没有直接写出地址。它只是说:地址在 SI 里
所以 CPU 先看 SI 的内容,再去内存取数据。这就叫寄存器间接寻址。
4. 寄存器间接寻址适合数组和表格
比如你有一段连续数据:
TABLE[0]TABLE[1]TABLE[2]...
可以让 SI 指向当前元素。每取一个元素后:INC SI 或者:ADD SI, 2
就能访问下一个元素。
所以 SI、DI 经常用于数组、字符串、表格处理。
存储器寻址 3:基址变址寻址 基址变址寻址是:
EA = 基址寄存器 + 变址寄存器
基址寄存器只能是:BX 或 BP
变址寄存器只能是:SI 或 DI
所以合法组合只有:[BX + SI]
[BX + DI][BP + SI][BP + DI]
1. 例子MOV [BP + DI], AX
意思是:EA = BP + DI 把 AX 写入该内存地址处
如果用了 BP,默认段寄存器是 SS。
所以:MOV [BP + DI], AX
默认是:SS:[BP + DI]
2. 图 4.5 怎么看?

图中类似:SS = 3000H BP = 2000H DI = 1000H
先算 EA:EA = BP + DI = 2000H + 1000H = 3000H
再算物理地址:SS × 10H + EA= 3000H × 10H + 3000H = 33000H
所以访问的是物理地址 33000H 开始的内存单元。
默认段寄存器规则 这一页非常重要。
8086 存储器寻址时,默认段寄存器通常是:
BX、SI、DI 参与寻址 → 默认 DSBP 参与寻址 → 默认 SS
例如:MOV AX, [BX] 默认:DS:[BX]
MOV AX, [SI] 默认:DS:[SI]
MOV AX, [BP] 默认:SS:[BP]
MOV AX, [BP + DI] 默认:SS:[BP + DI]
如果你想改默认段,可以加段超越:
MOV AX, ES:[SI] MOV AX, DS:[BP]
五、哪些基址变址写法是错误的?
课本给了几条错误例子。1. [BX + CX] 错
MOV [BX + CX], AX错,因为 CX 不能作为变址寄存器。
8086 中变址寄存器只能是:SI、DI
2. [BX + BP] 错 MOV [BX + BP], AX
错,因为 BX 和 BP 都是基址寄存器,不能两个基址寄存器相加。
合法形式必须是:基址寄存器 + 变址寄存器
也就是:BX/BP + SI/DI
3. MOV [BX + DI], ARRAY 错
如果 ARRAY 是变量名,那么它表示内存操作数。
MOV [BX + DI], ARRAY
就变成:内存 ← 内存
两个操作数都在内存中,普通双操作数指令不允许这样。
应该通过寄存器中转:
MOV AX, ARRAY MOV [BX + DI], AX
或者根据数据宽度用 AL、AX 等寄存器。
目前关键的知识框架
一条指令 =操作码 + 操作数信息
操作码告诉 CPU 干什么操作数告诉 CPU 对谁干寻址方式告诉 CPU 怎么找到操作数
8086 指令编码大致:第 1 字节:OP code + d + w 第 2 字节:mod + reg + r/m后面可能跟位移量 displacement后面可能跟立即数 immediate前面可能有段超越前缀 prefix
常见寻址方式目前学到:
立即寻址:MOV AX, 1234H寄存器寻址:MOV CL, DL直接寻址:MOV AX, [1000H]寄存器间接寻址:MOV AX, [SI]基址变址寻址:MOV AX, [BX+DI]
默认段寄存器:
BX、SI、DI → DSBP → SS
操作数在内存中时:
先算 EA再加段基址得到物理地址再访问内存
六.认清:1. MOV AX, SI 和 MOV AX, [SI] 不一样
MOV AX, SI是寄存器寻址:AX = SI
MOV AX, [SI] 是寄存器间接寻址:
AX = DS:SI 指向的内存中的一个字方括号非常关键。
2. [1000H] 不是物理地址 1000H
MOV AX, [1000H] 默认是:DS:[1000H]
物理地址是:DS × 10H + 1000H不是直接访问物理地址 1000H。
3. BP 默认段是 SS
只要寻址中使用 BP,默认段一般是 SS。
例如:MOV AX, [BP+DI]
默认是:SS:[BP+DI] 不是 DS。
4. 两个内存操作数不能直接操作
不能:MOV [2000H], [1000H]
要写成:
MOV AX, [1000H] MOV [2000H], AX
下一次继续往后读时,重点会进入更多寻址方式,比如寄存器相对寻址、基址变址相对寻址、I/O 端口寻址、转移地址寻址,然后就会正式进入具体指令类别。
