← 返回 计组与微机控制

计组与微机控制

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

7.1 x86寻址方式 图 1

物理地址: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 怎么看?

7.1 x86寻址方式 图 2

图中类似: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 端口寻址、转移地址寻址,然后就会正式进入具体指令类别。