汇编基础:寻址方式
2017-06-10
这一篇我大致概括下计算机的寻址方式,因为自己在汇编上也不是知道很多,所以难免有错误之处,还希望高手拍砖。希望这一系列文章能为大家学习汇编提供一个平台。
首先还是说下指令操作数,Intel 8086/8088CPU的指令系统中锁需操作数有以下4种:
(1)寄存器操作数:操作数在CPU的通用寄存器或段寄存器中
(2)立即数操作数:操作数在指令中直接给出
(3)存储器操作数:操作数在存储器的存储单元中
(4)I/O操作数:操作数在输入输出端口的存储单元中
根据操作数来源不同,将指令寻址方式分为寄存器寻址、立即数寻址、存储器寻址和I/O寻址四大类,下面来细说这四类方式。
一、寄存器寻址
在寄存器寻址方式中,操作数来自CPU的某个/某两个通用寄存器中或段寄存器中(CS除外),16位的寄存器操作数可以是AX、BX、CX、DX、SI、DL、SP、BP、DS、SS和ES,8位寄存器可以是AL、AH、BL、BH、CL、CH、DL、DH。由于存取操作数就在CPU内部进行,不需要访问存储器二执行总线周期,所以执行速度非常快,另外通用寄存器数目较少,编码所需的二进制位就少,因而使用寄存器寻址可以有效的减少指令宽度。
例如:MOV AX, BX;将寄存器BX中的内容传送给寄存器AX中
若执行前AX=1234H, BX=5678H,则指令执行完后AX=5678H,BX中内容不变。
二、立即数寻址
在立即数寻址中指令操作数直接放在代码中。它是紧跟在指令操作码后面的一个可用的8位或16位二进制补码表示的有符号数,即操作数的存放地址是指令操作码的下一个单元,这种操作呗成为立即数。
例如:MOV AX, 1234H立即数1234H作为源操作数送入寄存器AX中
指令执行后的结果是寄存器AX的值是1234H
三、存储器寻址
在存储器寻址方式下,指令操作数一般是代码段以外的数据段,堆栈段和附加段中的存储单元,指令给出的是存储单元地址或者是存储单元地址的表达式。在汇编语言中一个存储单元地址都是使用逻辑地址来表示的。即段基值:偏移量。其中段基值在某个段寄存器中。偏移量表示了该存储单元与段基值之间的距离,它是由CPU的执行单元EU来确定和计算有效地址EA。执行指令时,CPU首先根据操作数字段提供的地址信息,由执行单元EU计算出有效地址EA,再由总线接口单元BIU根据公式:物理地址=段基值X16+EA计算出操作数的物理地址,有效地址EA由3个地址分量组合而成:
(1)位移量
(2)基址
(3)变址
一般来说,双操作数指令的源操作数和目的操作数不能同时为存储器操作数,存储器寻址方式按EA计算方式的不同可分为:直接寻址、存储器间接寻址、基址寻址/变址寻址、基址变址寻址、相对基址变址寻址和串操作寻址6种。
1.直接寻址
直接寻址时存储器寻址中最简单的一种,即操作数的有效地址EA只由位移量组成,即EA=位移量,位移量是直接包含在指令中的,和指令操作码一起存放在代码段中,而操作数则存放在数据段中,直接寻址方式不涉及其他寄存器。使用直接寻址的实例:
MOV BX, VAR ;等价于MOV BX, DS:VAR
MOV AX, [100H];等价于MOV AX, DS:[100H]
例如:MOV AX, [1234H];将当前数据段偏移1234H个字节的子存储单元内容传送给寄存器AX。
设(DS)=2000H, 那么要访问的子存储单元的物理地址为2000H*16+1234H=21234H,
如果该字节的存储单元的内容是5678H,则(AX)=5678H。
2.存储器间接寻址
在存储器间接寻址方式中,指令的操作数在存储器中,操作数的有效地址EA不像直接寻址方式那样直接存放在指令中,而是由基址寄存器BX、BP或变址寄存器SI、DI提供。
如果指令中使用的是BX、SI、DI,则操作数在数据段中,段基值在数据段寄存器DS中,则操作数物理地址为:
物理地址=16*(DS)+(BX)/(SI)/(DI)
如果指令中实用的是BP,则操作数在堆栈段中,段基值在堆栈段寄存器SS中,操作数的物理地址为:
物理地址=16*(SS)+(BP)
3、基址寻址/变址寻址
基址寻址/变址寻址也没成为寄存器相对寻址,其操作数的有效地址EA是一个基址寄存器(BX或BP)或者是变址寄存器(SI或DI)的内容与指令中制定的一个8位或16位的位移量之和,即
有效地址EA=(BX)/(BP)/(SI)/(DI)+8位位移量/16位位移量
使用BX/BP寻址时即成为基址寻址,使用SI/DI时,即成为变址寻址。
如果使用寄存器BX、SI、DI,则隐含使用的段寄存器为DS, 如果使用寄存器BP则隐含的使用堆栈寄存器SS, 若操作数前指定了段寄存器,那么以指定的段寄存器为准。即操作数的物理地址为:
物理地址=16*(DS)+(BX)/(SI)/(DI)+8位位移量/16位位移量
或者 物理地址=16*(SS)+(BP)+8位位移量/16位位移量
使用基址寻址/变址寻址的示例如下:
MOV AL, 10H[BX];等价于MOV AX, DS:10H[BX]
MOV AL, 20H[SI];等价于MOV AL, DS:20H[SI]
MOV AH, ES:30H[BX]
例:MOV AX, 10H[BX]
设(DS)=2000H, (BX)=20H, (20030H)=1234H, 则操作数的物理地址=16*2000H+10H
+20H=20030H, 执行结果是(AX)=1234H
4、基址变址寻址
基址变址寻址的操作数有效地址EA是一个基址寄存器(BX或BP)的内容,一个变址寄存器(SI或DI)的内容与指令中制定的一个8位或16位的位移量之和,即:
有效地址EA=(BX)/(BP)+(SI)/(DI)+8位位移量/16位位移量
如果基址寄存器为BX,那么隐含使用的数据段寄存器DS,如果基址寄存器为BP。则隐含使用的是堆栈寄存器SS那么以指定的段寄存器为准,因此,操作数的物理地址为:
物理地址=16*(DS)+(BX)+(SI)/(DI)+8位位移量/16位位移量
或者 物理地址=16*(SS)+(BP)+(SI)/(DI)+8位位移量/16位位移量
使用基址变址寻址的方式示例如下:
MOV AX, 10H[BX][SI];等价于MOV AX, DS:10H[BX][SI]
MOV 20H[BP][DI], CX;等价于MOV SS:20H[BP][DI], CX
前面说的几种存储器寻址方式中,比如直接寻址、寄存器间接寻址、基址寻址/变址寻址实际上都是基址变址寻址的特例,位移量可以用常数表示,也可以用变量表示,位移量可放在方括号前面,也可放在方括号中同寄存器一起写成一个地址表达式,例如下面几种写法便是等价的:
MOV VAR[BX][SI], AX
MOV [BX+VAR][SI], AX
MOV [BX][SI+VAR], AX
MOV [BX+SI+VAR], AX
例:MOV AX, 10H[BX][SI]
设(DS)=2000H, (BX)=1000H, (SI)=3000H, (24010H)=1234H.则
操作数的物理地址=16*2000H+1000H+3000H+10H=24010H, 执行结果(AX)=1234H
5、串操作寻址
Intel 8086/8088CPU提供了一些专门用于串操作的指令,串操作指令操作数虽然在存储器中,但是它们不使用前面我们所说的各种寻址方式,而是隐含使用了两个变址寄存器SI和DI,串操作指令在寻找源操作数时,隐含使用SI作为地址指针,源操作数地址由DS:[SI]提供,寻找目的操作数时,隐含使用DI作为地址指针,目的操作数地址由ES:[DI]提供,在每次操作完后,指令将自动修改SI和DI的值,使它们指向下一个单元,指针修改的方向由CF决定,这也就是我在另一篇文章中所说的标志寄存器(http://yiluohuanghun.blog.51cto.com/3407300/938213)。
四、I/O寻址
I/O指令是CPU与外部设备进行通讯的最基本的途径,这意味着即使使用DOS功能调用或BIOS运行程序,其例行程序本身也是用I/O指令与外部设备进行数据交换的。
1、输入指令
一般格式为IN AL, PORT
2、输出指令
一般个事为OUT PORT, AL
至此为止,我们已经把计算机的几种寻址方式一一列举,希望对大家有帮助!