指令系统(二)
寻址方式(一)
在指令中,用于说明操作数所在地址的方法就称为寻址方式
8086 CPU指令系统的寻址方式分为两类。
-
数据的寻址方式:寻找指令操作所需数据的方法。
-
转移地址的寻址方式:寻找转移指令所需程序地址的方法。
数据的寻址方式
一共有8种:立即寻址、寄存器寻址、直接寻址、寄存器间接寻址、寄存器相对寻址、基址-变址寻址、基址-变址-相对寻址(后五类可以统称存储器寻址)和隐含寻址
MOV
指令数据传送图:
注意图中只有立即数和段寄存器是单向箭头,说明:
- 立即数只能做SRC(源操作数)
- 段寄存器只能做DST(目的操作数)
立即寻址
将8位或16位数据直接放在指令之后,这种操作数的寻址方式称为立即寻址
例:MOV AX, 1234H
寄存器寻址
指令的操作数存放在寄存器中,这种操作数的寻址方式称为寄存器寻址。16位数据可以存放在寄存器 AX、BX、CX、DX、SI、DI、SP、BP、DS、ES、SS、CS
中;8 位数据可以存放在寄存器AL、AH、BL、BH、CL、CH、DL、DH
中
例:MOV AX, BX
功能:将BX寄存器中的数据存入AX寄存器中
注意
-
传送类型的寄存器要一致,解决方法参考PTR操作符
比如:
MOV [0200H], 56H; [0200H]是个寄存器,0200H是寄存器地址,寄存器类型不知道 ;解决 MOV WORD PTR [0200H], 56H
-
注意:立即数和段寄存器(
DS、ES、SS
)不能直接交互,看上图,图中立即数和段寄存器没有箭头直接连接解决:二者交互要通过存储单元或者通用寄存器
例:
MOV DS, 1500H;语法错误 ;解决 MOV AX, 1500H MOV DS, AX
-
CS、IP
不能做DST
,用户无权更改其值例:
MOV CS, AX;语法错误 MOV AX, CS;正确 MOV IP, AX;语法错误 MOV AX, IP;正确
其他语法规则:堆栈操作,只能按字操作
存储器寻址
要寻找的操作数(OPR
)在存储器某单元中,存储操作数单元的段内偏移地址(EA
)可以由以下5种方法求得
直接寻址
操作数保存在存储单元中,其16位的偏移地址(有效地址)直接在指令中给出,这种方式称为直接寻址
例1:
MOV AL, [2000H]
分析
- 存储器段地址
DS
(默认),偏移地址2000H
,即DS:2000H
- 目的寄存器是
AL
,字节型单元,所以DS:2000H
处存储的是字节型数据 - 将
DS:2000H
处存储的字节型数据送入AL
例2:将DAT1
的数据送入AL
(直接寻址)
DATA SEGMENT ;定义数据段
DAT1 DB 12H ;定义两个变量
DAT2 DB 34H
DATA ENDS
CODE SEGMENT ;定义代码段
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX ;将数据段的段地址送人DS
MOV AL, DAT1
CODE ENDS
END START
结果:
分析代码 MOV AL, DAT1
,AL
和DAT1
分别是什么寻址
根据上节知道,变量有5个属性,DAT1代表的就是一个地址(储存变量数据存储器的地址)
所以DAT1是直接寻址,而AL是寄存器寻址
注意:两存储器之间不能直接操作
MOV DAT2, DAT1;语法错误
例3:将字型数据传给字节型(关注第11-14行代码)
DATA SEGMENT ;定义数据段
DAT1 DB 12H ;定义两个变量
DAT2 DB 34H
DATA ENDS
CODE SEGMENT ;定义代码段
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX ;将数据段的段地址送人DS
MOV DAT1, AX;语法错误,类型不一致
;修改
MOV WORD PTR DAT1, AX
MOV AL, DAT2 ;用于查看DAT2内的数据
CODE ENDS
END START
这会有个问题,刚才还定义了一个 DAT2
,这个变量还会存在吗,其中的数据会发生变化吗
演示:
语句执行前:
第一个空间存储的是DAT1
,第二个空间存储的是 DAT2
寄存器 AX
内是0710H
执行后:
数据段内,DAT2
的数据被覆盖了
但 DAT2
这个变量还存在
寄存器间接寻址
操作数保存在存储单元中,其段内偏移地址存放在寄存器中。只能使用 BX、SI、DI
注意:
BX
默认为DS
段的基址,BP
默认为SS
段,也就是堆栈段的基址
例4:将DAT1
的数据送入AL
(寄存器间接寻址)
MOV BX, OFFSET DAT1 ;
MOV AL, [BX] ;(DS:(BX))-->AL
分析:BX
采用寄存器间接寻址
寄存器相对寻址
操作数保存在存储器中,其段内偏移地址为一个基址寄存器或变址寄存器的内容与一个8位或16位的位移量(disp)之和:
MOV [BP], AL;(SS:(BP)+0)<--AL
编译后:
MOV DAT1+3, AL
分析:DAT1+3
是直接寻址,将 AL
内的数据,存入DAT1+3
所指向的空间内
下面改用寄存器间接寻址
MOV [BX]+3, AL;等价于MOV 3[BX], AL
结果展示:
未转移前的数据段:
未转移前的 AL
:
转移后的数据段:
注意:
MOV BX, 0 ;清零
MOV AL, 0 ;清零
MOV DAT1[BP], AL;DS:OFFSET DAT1+(BX)<--AL
-
因为
DAT1
在DS
中定义,所以最后一行代码段地址是DS
-
MOV [BX]+3, AL
也可写成MOV [BX+3], AL
例:CPU执行以下代码
PUSH AX
PUSH BX
PUSH CX
将压入堆栈的(AX)放入DX中,但不能破坏 SP
指针
分析:
PUSH
前,DX
中数据为0:
PUSH
后:
;寄存器相对寻址
MOV BP, SP;使BP也指向FFFA
MOV DX, [BP]+4
注意:代码中为什么 +4
,因为堆栈操作是按字操作,且指向栈底,每次 PUSH
地址 -2
,所以 FFFA+4=FFFE
(AX
的地址)
结果:
DX
获取到了值,且 SP
没有改变
基址-变址寻址
操作数保存在存储器中,其段内偏移地址为一个基址寄存器和一个变址寄存器的内容之和:
例:
MOV AX, [BX][SI]
基址-变址-相对寻址
操作数保存在存储器中,其段内偏移地址为一个基址寄存器内容、一个变址寄存器内容、一个 8 位或 16 位的位移量(DISP)之和:
例:用基址-变址-相对寻址,将DAT1
清零
代码:
MOV BX, OFFSET DAT1
MOV SI, 0
MOV AL, 0
MOV [BX][SI], AL;((BI)+(SI))<--AL,基址-变址寻址
结果:
在将 DAT2
的值清零
代码:
MOV [BX][SI]+1, AL;((BI)+(SI)+1)<--AL,基址-变址-相对寻址
结果:
隐含寻址
有些指令的指令码中不包含指明操作数寻址方式的部分,但操作码本身隐含指明了操作数的地址
例:
PUSH AX; 1.SP<--(SP)-2
; 2.(SS:(SP))<--(AX)
压栈操作只给出了源操作数,但本身隐含了目的操作数((SS:(SP))
)
后面讲的字符串操作指令,均为隐含寻址