Intel 8086 是因特尔早期研制的一款16位经典微处理器芯片,是x86架构的鼻祖。
为深入学习该系列处理器汇编语言,本文将总结 8086 指令系统的寻址方式。

寻址与指令


寻址方式(Addressing Mode)是确定当前指令操作数地址以及下一条要执行指令地址的方法。

简单说就是在指令中操作数和下一条指令(地址)是如何获取的,是直接给出,还是给出提示信息去查找。

数据寻址


立即寻址

操作数直接放在指令的操作数码段中,故立即寻址不会访问寄存器,存储器,指令执行速度快。

图形示意:

立即寻址立即寻址

代码示意:

1
mov al, 5	;执行结果:(al) = 5      ["()"表示取内容,以下皆如此]

寄存器寻址

操作数存放在寄存器中,而在指令中给出寄存器的标号,指令执行时会到这个寄存器中取出相应的操作数,即访问寄存器,不访问存储器,速度也很快。

图形示意:

寄存器寻址寄存器寻址

代码示意:

1
mov ax, bx	;假设(bx) = 30H,则执行结果为:(ax) = 30H

存储器寻址说明

1.有效地址

1
有效地址(EA)= 位移量(disp) + 基址(base) + 变址(index)

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

2.段前缀使用规则

8086 允许程序员用段跨越前缀来改变系统所指定的默认段,如:允许数据存放在 DS 以外的段中,使用时指明段前缀,但是有些情况是不可以修改的。

(1) 串处理操作中目的串必须用 ES 段,即默认为 ES:DI,不可修改。
(2) 压栈(push)、弹栈(pop)必须使用 SS 段,即默认为 SS:SP 不可修改。
(3) 指令必须存放在 CS段 中。

访存类型 所用段及段寄存器 缺省时使用规则
指针 代码段 CS 取指
堆栈 堆栈段 SS 所有的堆栈操作/任何用 BP 作为基址寄存器的访存
局部数据 数据段 DS 除堆栈以及串处理操作中目的串以外的数据访问
目的串 附加段 ES 串处理操作中的目的串

直接寻址

操作数的有效地址只包含位移量一种成分,有效地址 = 位移量 ,而位移量就存放在指令的操作数码段中。
注意
1、为了防止指令字过长,规定双操作数指令中的两个操作数中,只能有一个使用存储器寻址方式。
2、注意区分有效地址别称 — 偏移地址(Offset Address)与位移量(displacement),这是两个概念。

图形示意:

直接寻址直接寻址

代码示意:

1
mov ax, [2000H]		;假设 (ds) = 3000H ,则执行结果为:(ax) = (32000) ,即取出存储单元 32000H-32001H 位置的值赋给 ax

位移量可以像高级语言一样用变量表示,而且还可以为这个位移量指定段前缀。

寄存器间接寻址

操作数在存储器中,而其有效地址存放在某个寄存器中,可用寄存器有 BX、BP、SI、DI。

区别于寄存器寻址,前者操作数存放在寄存器中,在指令中存放相应的寄存器号码,不需要访存;后者的寄存器存放操作数的有效地址,而操作数本身在存储器中。指令要先通过该寄存器获取操作数有效地址,在通过该地址访存获取操作数。
同样也可以为其指定其他段前缀。

图形示意:

寄存器间接寻址寄存器间接寻址

代码示意:

1
mov ax,[bx]	;假设 (ds) = 2000H,(bx) = 1000H ,则执行结果为:(ax) = (21000) ,即取出存储单元 21000H-21001H 位置的值赋给 ax

寄存器相对寻址

操作数有效地址等于寄存器内容与指令中指定位移量之和,可使用寄存器有 BX、BP、SI、DI。与寄存器间接寻址相比,指令中多了位移量。

有效地址(EA)= 基址/变址 + 位移量。

图形示意:

寄存器相对寻址寄存器相对寻址

代码示意:

1
mov ax, count[si]/[count+si]	;假设 (ds) = 3000H ,(si) = 2000H ,count = 3000H ,则执行结果为:(ax) = (35000H),即取出存储单元 35000H-35001H 位置的值赋给 ax

基址变址寻址

操作数有效地址等于基址寄存器与变址寄存器内容之和,可使用寄存器有 BX、BP、SI、DI。

有效地址(EA)= 基址 + 变址。

图形示意:

基址变址寻址基址变址寻址

代码示意:

1
mov ax, [bx][di]/[bx+di]	;假设 (ds) = 2100H ,(bx) = 0158H ,(di) = 10A5H ,则执行结果为:(ax) = (221FDH),即取出存储单元 221FDH-221FEH 位置的值赋给 ax

相对基址变址寻址

操作数有效地址是基址寄存器与变址寄存器的内容和指令中指定的位移量之和。相比前面多了位移量,而寻址方式命名中多了相对二字。

有效地址(EA)= 基址 + 变址 + 位移量

总结
(1) 只有位移量一项时叫直接寻址,除位移量外,还有其他项的叫做相对XX寻址/XX相对寻址
(2) 存储器寻址可以使用的寄存器只有四个,因为要存放的都是地址。

图形示意:

相对基址变址寻址相对基址变址寻址

代码示意:

1
mov ax, count[bx][si]/[count+bx+si]		;假设 (ds) = 3000H ,(bx) = 2000H ,(si) = 1000H ,count = 0250H ,则执行结果为:(ax) = (33250H),即取出存储单元 33250H-33251H 位置的值赋给 ax

应用
这种寻址方式通常用于对二维数组的寻址。也为堆栈处理提供了方便,一般(BP)可指向栈顶,从栈顶到数组的首地址可用位移量表示,变址寄存器可用来访问数组中的某个元素。

转移寻址


段内与段间:两者区别就在于地址跳转时是否跨越当前段范围,段内就是不跨越,相应的段跨越前缀就不用修改,只需要修改偏移量;段间需要跨越段范围,段跨越前缀要和偏移量同时修改。

直接与间接:前者指直接给出即将跳转地址与当前地址(段跨越前缀的偏移和有效地址的偏移)之差,而后者需要通过像数据相关寻址一样间接获取这个差值。

段内直接寻址

转向的有效地址是当前IP寄存器的内容和指令中指定的8位或16位位移量之和,所以它是一种相对寻址方式。
指令中的位移量是转向的有效地址与当前 IP 值之差,所以当这一程序段在内存中的不同区域运行时,这种寻址方式的转移指令本身不会发生变化,这是符合程序的再定位要求的。

图形示意:

段内直接寻址段内直接寻址

代码示意:

1
2
jmp near ptr progia
jmp short quest

其中,progia和quest均为转向的符号地址,在机器指令中,用位移量来表示。
在汇编指令中,如果位移量为16位,则在符号地址前加操作符near ptr,如果位移量为8位,则在符号地址前加操作符SHORT。
条件转移指令只能使用段内直接寻址的8位位移量。

段内间接寻址

转向有效地址是一个寄存器或存储单元的内容。(这个寄存器或存储单元的内容可以用数据寻址方式中除立即数以外的任何一种寻址方式取得),所得到的转向的有效地址用来取代IP寄存器的内容。

图形示意:

段内间接寻址段内间接寻址

代码示意:

1
2
jmp bx
jmp word ptr[bp+table]

段间直接寻址

在指令中直接提供了转向段地址和偏移地址,所以只要用指令中指定的偏移地址取代IP寄存器的内容,用指令中指定的段地址取代CS寄存器的内容就完成了从一个段到另一个段的转移操作。

图形示意:

段间直接寻址段间直接寻址

代码示意:

1
jmp far ptr next	;next 为转向的符号地址,far ptr 则是表示段间转移的操作符。

段间间接寻址

用存储器中的两个相继字的内容来取代IP和CS寄存器中的原始内容,以达到段间转移的目的。(这里,存储单元的地址是由指令指定除立即数方式和寄存器方式以外的任何一种数据寻址方式取得)

图形示意:

段间间接寻址段间间接寻址

代码示意:

1
jmp dword ptr[inters+bx]

其中,[inters+bx]说明数据寻址方式为寄存器相对寻址方式,dword ptr为双字操作符,说明转向地址需取双字为段间转移指令。依次作为IP和CS的值。