8086 处理器寻址方式

请注意:本文编写于 ,其中某些信息可能已经失去时效性。

前言

本文主要描述了何为寻址,寻址能力的计算以及 8086 处理器的寻址方式有哪些。

寻址

什么是寻址?

内存中每一个字节(8bit)都有一个对应的内存地址,CPU 去访问某一具体内存地址的过程称为寻址。

寻址能力与什么有关?

CPU 的寻址能力一般使用寻址空间来表示,寻址空间的大小决定了 CPU 可支持的最大内存容量,以字节为单位。寻址空间的大小由地址总线的地址寄存器宽度(位数)决定,假设地址总线位数为 N 位,则寻址空间为 2 的 N 次方字节(因为计算机使用的是二进制所以是 2 的 N 次方)。

特殊的 8086 处理器

8086 处理器有 20 位地址总线,可传送 20 位的地址,寻址空间为 1M。

而 8086 处理器是 16 位结构的处理器即 8086 内部的寄存器位数为 16 位,如果按照这个数据处理能力 8086 只能发送出 16 位的地址,表现出的寻址能力只有 64 KB。

为了解决上述问题,在 8086 处理器内部采用了一种使用两个 16 位地址(段地址:偏移地址)合成一个 20 位物理地址的方案。

具体计算公式为:物理地址 = 段地址左移四位 + 偏移地址。

指令

在汇编语言中,一般的指令格式为:指令代码 目的操作数,源操作数。

目的操作数和源操作数统称为操作数,而寻址方式的主要表现形式就是体现在两个操作数的表现形式上。

8086 处理器的寻址方式

8086 处理器有七种基本寻址方式:

寄存器寻址

指令执行时,操作数位于寄存器中,可以直接从寄存器中获取。

1
2
3
mov ax,cx     ; 此条指令中目的操作数和源操作数使用的都是寄存器寻址
add bx,0xf000 ; 此条指令中目的操作数使用的是寄存器寻址,源操作数使用的是后面要介绍的立即寻址
inc dx ; 这是一条比较特殊的指令,它只有目的操作数,并且使用的是寄存器寻址

立即数寻址

立即数寻址又称为立即寻址,指的是操作数为立即数的寻址方式。

所谓立即数指的是直接包含在指令中且紧跟在操作码后可以立即从指令中获取的操作数。

在立即寻址中立即数可以是 8 位的,也可以是 16 位的(注意我们的大前提是在 8086 处理器下)。这种寻址方式主要用于给寄存器或存储单元赋初始值,立即寻址是这七种基本寻址方式中速度最快的寻址方式。

注:在实例代码中会有一个特殊的立即寻址例子。

1
2
mov ax,oxf000   ; 此条指令中目的操作数使用的是寄存器寻址,源操作数使用的是立即寻址
mov ax,label_a ; 注意此条指令的源操作数,它采用的也是立即寻址,这里的 `label_a` 虽然是一个标号但是标号是数值的等价形式,它代表了所在位置的汇编地址,在编译阶段被转换为一个立即数

阶段小结

此前介绍的两种寻址方式:寄存器寻址和立即数寻址均未涉及到内存地址,都是在指令层面或更高级的存储空间(寄存器)层面的数据提取和存储。

内存寻址

寄存器寻址的操作数位于寄存器中,立即寻址的操作数位于指令中,是指令的一部分。这是两种速度比较快的寻址方式,但它们也有局限性:一方面,我们不可能总是知道要操作的数是多少,因此也就不可能总是在指令上使用立即数;另一方面,寄存器的数量有限,不可能总指望在寄存器之间来回传递数据。

而内存恰巧拥有较大的容量,所以在指令中使用内存地址来表明要操作的内存中的数据是比较理想的方案。下面我们要介绍的五中寻址方式才是真正的在内存汇总寻找所需数据的寻址方式,它们统称为内存寻址。

在正式介绍内存寻址之前需要先理解一个概念:有效地址,即偏移地址。有效地址是一个 16 位的无符号数,表示操作数所在内存单元到段首的距离。

有效地址(Effective Address,EA)= 偏移量(disp)+ 基址(base)+ 变址(index)。

偏移量:存放在指令中的数,但它不是一个立即数,而是一个地址,可以用变量或标号表示。
基址:存放在基址寄存器(BX,BP)中,有效地址的基址部分。
变址:存放在变址寄存器(SI,DI)中,有效地址的变址部分。
三者都是可选的,但必须存在一个。

基本规则

  1. 为了防止指令过长,双操作数指令中只能有一个使用存储器寻址方式;
  2. 所有表示内存地址的操作数都需要使用 [] 包裹起来;
  3. 数据默认存放在 DS 段中且默认隐藏前缀,也可以通过显示标注段前缀来覆盖默认值;
  4. 串指令中的目的操作数必须使用 ES 段作为前缀,默认为 [ES:DI],且不能修改;
  5. push 和 pop 指令必须使用 [SS:SP],且不可以修改;
  6. 所有指令内容必须存放在 CS 段中;

直接寻址

操作数所表示的有效地址仅包含偏移量一种成分,即有效地址 = 偏移量。

1
2
3
mov ax, [0x5c0f]            ; 目的操作数使用的是寄存器寻址,源操作数使用的是直接寻址,地址为:ds:0x5c0f
mov word [0x0230], 0x5000 ; 目的操作数使用的是直接寻址,地址为:ds:0x0230,源操作数使用的是立即数寻址
xor byte [es:label_b], 0x05 ; 目的操作数使用的是直接寻址,地址为:es:label_b,这里的 label_b 是一个标号,但在编译时会被编译为标号对应的偏移量,源操作数使用的是立即数寻址

寄存器间接寻址

操作数所表示的有效地址存放在 BX BP SI DI 中的某一个寄存器中。此种寻址方式与寄存器寻址的区别在于:在寄存器寻址方式下寄存器存储的是待操作数据本身,而在本寻址方式下寄存器存储的是待操作数据所在的内存地址段内偏移量。

1
2
mov ax, [bx]    ; 目的操作数使用的是寄存器寻址,源操作数使用的是寄存器间接寻址,地址为:ds:bx
mov ax, [es:bx] ; 目的操作数使用的是寄存器寻址,源操作数使用的是寄存器间接寻址,地址为:es:bx

寄存器相对寻址

操作数所表示的有效地址是 BX BP SI DI 中的某一个寄存器的内容和给出的偏移量之和(差)。

1
mov ax, [bx + 0x0030] ; 目的操作数使用的是寄存器寻址,源操作数使用的是寄存器相对寻址,地址为:es:bx+0x0030

基址变址寻址

操作数所表示的有效地址是基址寄存器(BX,BP)和变址寄存器(SI,DI)所表示的内容之和。

1
mov ax, [bx+si] ; 目的操作数使用的是寄存器寻址,源操作数使用的是基址变址寻址,地址为:es:bx+si

相对基址变址寻址

相对基址变址寻址是在基址变址寻址的基础上又多增加了一个偏移量的值。

1
mov ax, [bx+si+0x0030] ; 目的操作数使用的是寄存器寻址,源操作数使用的是基址变址寻址,地址为:es:bx+si+0x0030

参考

  1. 李忠:x86汇编语言-7.7
  2. EXP:8086 指令系统寻址
  3. Faron:8086中的七种寻址方式