寻址方式
定义
寻址方式:求操作数所在地或者所在存储器地址单元的方式。
指令中的操作数,大多数都在存储器单元当中,也可以在寄存器里面,也可以是在指令中立即给出的常数。我们都把求得她们的方式归属于寻址方式。
类型
寻址方式按求得的操作数的目的不同,可以分为两类:
-
数据用
-
程序要实现转移的地址用
如果要实现段内转移,就需要求得段内偏移地址给IP用,如果要实现段间转移,除了偏移地址外,还需要求得目的地的段地址给CS用。
要计算的数据的所在存储地址怎么得到,或者转移的地址内容的所在存储地址怎么得到,就需要用以一种寻址方式去求得。
关于数据的寻址方式
1.立即数寻址
要寻找的操作数在指令中立即给出,直接以常数给出。
如
mov AX,1234H
AX是目的操作数,1234H是源操作数,对于源操作数而言,采用的就是立即数寻址。指令中要传送给AX的数据在哪里呢?指令中立即给出了。这就叫立即数寻址。
要搞清楚8086立即寻址,就需要了解谁和谁之间可以传送
从图中可知,在8086当中,立即数只能作为源操作数。
立即数传送数据时要类型明确。
mov [0002H],15H
中括号里面表示的是地址,这条语句是把立即数15H送到地址为0002H的存储器单元中。
但是我们只知道地址是多少,不知道存储器单元的存储类型是什么?语法错误。类型不明确。这中问题只要源操作数和目标操作数有一方明确,双方均能明确(不一致另说)。双方不明确,类型不明确。
改
mov WORD PTR [0002H],15H
如果要传送数据给段寄存器,不能直接立即数传送,要按箭头走。
从图中也可以看出,段寄存器CS单独划分出来,因为用户无法改变CS的内容,和IP寄存器一样,开机的内容由操作系统完成。执行期间是由CPU完成转移指令改变。CS和IP不能做目标操作数,但是可以做源操作数。
2.寄存器寻址
指要寻找的操作数在某寄存器当中。
如
mov AX,BX
对于源操作数而言,要操作的数据在BX寄存器中,这就是寄存器寻址。同样的,目的操作数而言,也是寄存器寻址。
当源和目标是寄存器寻址时,一定要注意类型要一致。
如
mov AX,CL
AX是16位的,而CL是8位的,语法错误。
3.存储器寻址
指要寻找的操作数在存储器某单元中,存放操作数的单元的EA段内偏移地址,可以由以下5种寻址方式求得:
1.直接寻址
直接寻址就是在指令中直接写出存储单元的有效地址。
如
mov AL,[2000H]
将存储器单元地址为2000H的字节内容送给AL(实际上决定是字节内容的是AL的类型)
但这种方法不常用,一般都将地址符号化——变量名。
如
在DS段有下列变量定义:
dat1 DB 12H
dat2 DB 34H
...
实际中数据段定义的变量很多。
在CS段执行程序
mov AL dat1
dat1代表的就是一个地址,所以源操作数的寻址方式是直接寻址。在dat1里面的内容送给AL。执行完(AL)=12H。
mov dat2 dat1
源和目标操作数都采用直接寻址,想把dat1里内容直接送给dat2单元里面。但是语法错误。如上图3.3,寄存器之间可以互传数据,但是存储器单元之间不可以直接操作(任何操作)。不能直接传送数据,也不能直接运算。
只能通过寄存器做中转,读出来后,再将寄存器里面的值送给存储器。
当然也要遵循前后类型一致。如
mov WORD PTR dat1,AX
而不能直接进行数据传送,因为dat1是字节变量8位,AX是16位。
mov dat1,AX
2.寄存器间接寻址
指操作数在存储器中,段内偏移地址由寄存器间接给出。能做寄存器间接寻址的寄存器只有3个——BX,SI,DI。
这三个寄存器默认的段地址默认在DS数据段
如
dat1 DB 12H
dat2 DB 34H
把dat1内容送给AL,寄存器间接寻址方式为:
mov BX, OFFSET dat1
mov AL,[BX]
OFFSET dat1把dat1的偏移地址属性拿出来了,所以对于源操作数而言属于立即数寻址。
[BX]中括号里面是把BX的内容作为DS段的段内有效地址,属于寄存器间接寻址。
3.寄存器相对寻址
指的是操作数在存储器某个单元当中,有效地址由两部分组成:
第一部分在一个基址寄存器当中——BX,BP,SI,DI 四者之一。第二部分是一个8位或16位的DISP相对位移量。两部分之和就是操作数所在存储单元的地址。
如果相对位移量是一个常数,那么对应的逻辑段的段地址由寄存器部分默认决定给出。BX\SI\DI默认在DS段,BP默认在堆栈段SS。
如果相对位移量是一个变量,会自动取变量的段内偏移地址作为位移量,此时逻辑段的段地址由变量所在的段决定。
当然我们可以添加段超越前缀,改变寄存器指向的段地址。
这个方式容易和寄存器间接寻址混淆,但我觉得其实就是间接寻址基础上加上个位移量,但是又加上了一些规则。
如
mov [BP],AL
注意,[BP]是寄存器相对寻址,因为BP不能用作间接寻址。所以这条指令,是把AL的内容送给某个存储器单元,这个单元的地址一部分是BP内容,一部分为相对位移量,这里为0,即SS:(BP)+0。
ALmov [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定义在DS段,则dat1[BX]代表的存储器地址为 DS:OFFSET dat1+(BX)
BP相对寻址的目的
添加BP进行相对寻址的目的,是为了在不破坏堆栈指针SP的情况下,将堆栈里面的值读取出来
如
PUSH AX
PUSH BX
PUSH CX
现在将AX内容送给DX,但不能破坏SP内容,怎么做·?
mov BP,SP
mov DX,[BP]+4
4.基址、变址寻址
指的是操作数在存储器某个单元当中,有效地址由两部分组成:第一部分在一个基址寄存器当中——BX,BP两者之一;第二部分在一个变址寄存器中——SI、DI两者之一。两部分之和就是操作数所在存储单元的段内地址。段地址由基址寄存器默认决定。这种寻址方式叫做基址、变址寻址。
如,用基址、变址寻址方式,将dat1内容送给AL
dat1 DB 12H
dat2 DB 34H
...
mov BX,OFFSET dat1
mov SI,0
mov AL,[BX][SI]
5.基址、变址相对寻址
由第三种和第四种结合而来。
指的是操作数在存储器某个单元当中,有效地址由三部分组成:第一部分在一个基址寄存器当中——BX,BP两者之一;第二部分在一个变址寄存器中——SI、DI两者之一;第三部分是一个8位或16位的DISP相对位移量。三部分之和就是操作数所在存储单元的地址。这种寻址方式叫做基址、变址相对寻址。
同样的,和第三种一样,如果相对位移量是一个常数,那么对应的逻辑段的段地址由寄存器部分默认决定给出。BX默认在DS段,BP默认在堆栈段SS。
如果相对位移量是一个变量,会自动取变量的段内偏移地址作为位移量,此时逻辑段的段地址由变量所在的段决定。
如,用基址、变址相对寻址方式,将dat1内容送给AL
dat1 DB 12H
dat2 DB 34H
...
mov BX,0
mov SI,0
mov AL,dat1[BX][SI]
4.隐含寻址
隐含寻址的含义是,指令中并没有写明操作数,但是CPU知道操作数在哪个地方。
如
PUSH AL
指令只有单操作数,且是源操作数,没有指明目标操作数在哪里,但是CPU知道怎么做:
-
SP=(SP)-2
-
(SS:(SP))=AL
在8086中,字符串的指令,对于源和目标操作数都是隐含寻址。
实际当中,我们只需要选择其中之一作为寻址方式即可。