寻址方式
定义
寻址方式:求操作数所在地或者所在存储器地址单元的方式。
指令中的操作数,大多数都在存储器单元当中,也可以在寄存器里面,也可以是在指令中立即给出的常数。我们把求得它们的方式称为寻址方式。
类型
寻址方式按求得的操作数的目的不同,可以分为两类:
- 数据用
- 程序要实现转移的地址用
如果要实现段内转移,就需要求得段内偏移地址给IP用,如果要实现段间转移,除了偏移地址外,还需要求得目的地的段地址给CS用。要计算的数据的所在存储地址怎么得到,或者转移的地址内容的所在存储地址怎么得到,就需要用以一种寻址方式去求得。
本文讨论的是“关于数据”的寻址方式,共有9种:
- 立即数寻址
- 直接寻址
- 寄存器寻址
- 寄存器间接寻址
- 寄存器相对寻址
- 基址变址寻址
- 基址变址相对寻址
- 隐含寻址
- I/O端口寻址
1. 立即数寻址
立即数寻址意思是要寻找的操作数在指令中直接给出,如:
mov AX,4C00H
其中AX是目的操作数,4C00H是源操作数,对于源操作数而言,采用的就是立即数寻址。
2. 直接寻址
直接寻址就是在指令中直接写出存储单元的有效地址,如:
mov AL,[1000H]
指令执行后将存储器单元地址为1000H的字节内容送给AL,但这种方法不常用,一般都将地址符号化——利用变量名。
例如,在DS段有下列变量定义:
dat1 DW 1234H
dat2 DW 5678H
dat3 DW 9ABCH
...
如果我们在CS段执行语句:
mov AX dat1
其中dat1代表的就是一个地址,是1234H这一数据的首地址,所以源操作数的寻址方式是直接寻址,语句执行完后(AX)=1234H。
3.寄存器寻址
寄存器寻址是指要寻找的操作数存放在某寄存器当中,如:
mov BX,AX
对于源操作数而言,要操作的数据在AX寄存器中,这就是寄存器寻址。同样,对于目的操作数而言,其寻址方式也是寄存器寻址。
要注意以下问题:
当源和目的操作数都采用寄存器寻址时,一定要注意类型要一致。
如:
mov BX,AL
其中BX是16位的,而AL是8位的,类型不一致,很显然语法错误。
借此,我们可以给出一幅图来搞清楚mov指令数据传送的正确路径:
4.寄存器间接寻址
寄存器间接寻址是指操作数在存储器中,操作数的段内偏移地址由寄存器给出,由于不是在指令中直接给出操作数的地址/偏移地址,所以称该寻址方式为寄存器间接寻址。
能做寄存器间接寻址的寄存器只有3个——BX,SI,DI(也就是说,BP并不能作寄存器间接寻址用)。对于BX,SI,DI三个寄存器而言,它们默认的段地址存放在DS数据段。
现在我们定义两个字型数据dat1和dat2:
dat1 DW 1234H
dat2 DW 5678H
如果我们想把dat2数据送给AX,利用寄存器间接寻址方式如下:
mov BX,OFFSET dat2
mov AX,[BX]
OFFSET dat2把dat2的偏移地址属性拿出来了,所以“mov BX, OFFSET dat2”这条指令而言,其源操作数的寻址方式是立即数寻址。而[BX]的[ ]里面是把BX的内容作为DS段的段内偏移地址,因此属于寄存器间接寻址。
5.寄存器相对寻址
寄存器相对寻址指的是操作数放在存储器单元当中,而该单元的段内偏移地址由两部分组成,第一部分由一个基址寄存器给出——BX,BP,SI,DI 四者之一。第二部分是一个8位或16位的相对位移量(DISP)。两部分之和就是操作数所在存储单元的段内偏移地址。
那么该存储单元的段地址是什么呢?
- 如果相对位移量是一个常数,那么对应的逻辑段的段地址由寄存器对应的默认段给出。BX、SI、DI默认的段地址在DS段,BP默认在SS段。
- 如果相对位移量是一个变量(例如dat1),指令执行时会自动取该变量的段内偏移地址(即 offset dat1)作为位移量(DISP),此时逻辑段的段地址由变量所在的段决定。
- 当然,我们可以添加段超越前缀,改变寄存器指向的段地址。
特殊情况说明:
mov BYTE PTR [BP],AL
这条语句中,源操作数[BP]是寄存器相对寻址,因为BP不能用作间接寻址。所以这条指令,是把AL的内容送给某个存储器单元,这个单元的地址一部分是BP内容,一部分为相对位移量,这里为0,即SS:(BP)+0。
其他说明:
mov [BX]+3,AL
该语句的目的操作数是寄存器相对寻址,存储器单元的段内偏移地址为(BP)+3。这种寄存器相对寻址也可写成以下几种形式:
mov [BX+3],AL
mov 3+[BX],AL
;当偏移量在寄存器左边时,'+'可以省略,即:
mov 3[BX],A
当位移量是一个变量时。如:
dat1 DB 12H
mov dat1[BX],AL
则dat1[BX]代表的数据所在的存储器地址为 DS:OFFSET dat1+(BX)
BP相对寻址的目的
添加BP进行相对寻址的目的,是为了在不破坏堆栈指针SP的情况下,将堆栈里面的值读取出来。
假设我们先入栈了三个数据:
PUSH AX
PUSH BX
PUSH CX
现在我们想将AX内容送给DX,但不能破坏SP指针,how?
答案是:先把SP内容送给BP,再用寄存器相对寻址找到源操作数。很显然,SP寄存器并不能用作寄存器相对寻址。
mov BP,SP
mov DX,[BP]+4
6. 基址变址寻址
基址变址寻址指的是操作数在存储器单元当中,该单元的段内地址由两部分组成:第一部分在一个基址寄存器当中——BX或BP,第二部分在一个变址寄存器中——SI或DI。两部分之和就是操作数所在存储单元的段内地址。而段地址由基址寄存器默认对应的逻辑段决定。
例如,我们现在用基址变址寻址方式,将dat3内容送给AX:
dat1 DW 1234H
dat2 DW 5678H
dat3 DW 9ABCH
mov BX,OFFSET dat1
mov SI,4
mov AX,[BX][SI]
7. 基址变址相对寻址
基址变址相对寻址指的是操作数在存储器某个单元当中,该单元的段内有效地址由三部分组成:第一部分在一个基址寄存器当中——BX或BP;第二部分在一个变址寄存器中——SI或DI;第三部分是一个8位或16位的相对位移量(DISP)。三部分之和就是操作数所在存储单元的段内地址。
例如,我们现在用基址变址相对寻址方式,将dat2内容送给AX:
dat1 DW 1234H
dat2 DW 5678H
dat3 DW 9ABCH
mov BX,0
mov SI,0
mov AX,dat2[BX][SI]
8. 隐含寻址
指令中不指明操作数,但已隐含规定。
9. I/O端口寻址
① 直接端口寻址:端口地址由一个8位立即数表示,最多可访问256个端口。
② 间接端口寻址:端口地址由DX寄存去提供,最多可访问64K个端口。