指令中的操作数可能存放在:CPU寄存器、存储器、I/O端口。寄存器数量有限,可用3~5位编码(表示23~25个寄存器);I/O端口数量也不多,可用8位直接编码表示或16位DX寄存器间接表示;存储器容量巨大并在不断增长,而指令中操作数的位数有限,为了能灵活方便并大范围地访问存储器,开发了各种寻址技术和方法。
指令中操作数给出的地址称为形式地址A(Address),形式地址不一定能直接访问存储器,须经过某种运算方能得到直接访问存储器的有效地址(Effective Address,EA)。从形式地址生成有效地址的各种方式称为寻址方式。
CISC基本指令集的寻址方式包括对寄存器、I/O端口和存储器的寻址。其中对I/O端口有两种寻址方式、对存储器有6种寻址方式。
本书用寄存器名直接表示寄存器中的内容;地址加方括号表示存储器中相应地址单元的内容,方括号内可为无符号数(直接地址值)、寄存器名、寄存器与偏移量之和;地址加方括号也表示相应端口中的内容。
一般把操作数在段内的偏移地址称为有效地址(EA),把EA与段基址相加后得到的用于存储器寻址(出现在地址总线上)的地址称为物理地址。为简单起见,本书有时把物理地址也当作EA。
这种寻址方式就是上面所提到的第一种情况——参加操作的数据就包含在指令代码中。通常操作数写成Im,表示参加操作的数据是立即寻址方式。应该注意的是立即寻址方式只能出现在源操作数中,这一点在指令的应用中应牢牢记住。
例如:
MOV AL,08H ; 功能:AL←08H
MOV BX,100 ; 功能:BX←0064H
可以看出,指令中的源操作数部分的08H、100就包含在指令代码中,所以就是立即寻址方式。08H、100通常称为立即数(Im)。
这种寻址方式就是上面所提到的第二种情况——参加操作的数据在CPU的某个寄存器中。通常操作数写成R,表示参加操作的数据是寄存器寻址方式。
指令中可以引用的寄存器及其符号名称如下所示。
· 8位寄存器:AH、AL、BH、BL、CH、CL、DH和DL,通常写成R8。
· 16位寄存器:AX、BX、CX、DX、SI、DI、SP和BP,通常写成R16,用R代表8位与16位寄存器。
· 段寄存器:CS、SS、DS和ES,通常写成SegR。
例如:
MOV AL,08H ; 指令中的目标操作数AL就是寄存器寻址方式
MOV ES,BX ; 指令中的两个操作数ES和BX都是寄存器寻址方式
在指令中直接给出了参加操作数据的偏移地址,这种寻址方式为直接寻址。
段隐含:EA=DS×16+偏移地址。
段显式:EA=段寄存器×16+偏移地址。
例如:
MOV AX,[2200H] ; 功能:Ax←(DS:2200H)
MOV [2200H],AX ; 功能:(DS:2200H)←(AX)
可以看出,偏移地址2200H在指令代码中直接给出,所以就是直接寻址。而在汇编语言源程序中,由于汇编程序不支持数字化的直接地址,所以直接地址用内存变量来表示,所以上例可写成:
ORG 2200H
wData DW 1234H
MOV AX,wData ; 功能:Ax←(DS:2200H)
MOV wData,AX ; 功能:(DS:2200H)←(AX)
参加操作数据的偏移地址用SI、DI、BX和BP这4个寄存器之一来指定,称这种寻址方式为寄存器间接寻址方式。在不指定段的情况下,有下列规定:
· 若偏移地址用SI、DI和BX之一来指定,则其默认的段寄存器为DS。
· 若偏移地址用BP来指定,则其默认的段寄存器为SS。
例如:
MOV AL,[SI]
该指令是将DS段中的偏移量为SI的内存单元内容传给AL。
MOV AL,[BP]
该指令是将SS段中的偏移量为BP的内存单元内容传给AL。
参加操作数据的偏移地址是SI、DI、BX和BP这4个寄存器之一的内容和指令中的8位或16位偏移量之和,段寄存器的默认情况同寄存器间接寻址。在程序中,8位或16位偏移量通常用内存变量来表示。
例如:
MOV AL,count[SI]
该指令的功能是将DS段中的偏移地址为SI+count的内存单元内容传给AL。
参加操作数据的偏移地址是一个基址寄存器(BX、BP)和一个变址寄存器(SI、DI)的内容之和。在不指定段的情况下规定:如果基址寄存器为BP,则默认的段寄存器为SS;否则,默认的段寄存器为DS。
例如:
MOV AX,[BP][SI]
该指令的功能是将SS段中的偏移地址为(BP+SI)的内存单元内容传给AL,把(BP+SI+1)的内存段元的内容传给AH。
参加操作数据的偏移地址是一个基址寄存器(BX或BP)的值、一个变址寄存器(S1或DI)的值和指令中的8位或16位偏移量3项之和。
例如:
MOV BX,mask[BX][SI]
该指令的功能是将DS段中的偏移地址为(BX+SI+mask)内存单元的内容传给BL,把(BP+SI+mask+1)的内存单元的内容传给BH。
随着存储器容量的增长,可寻址的存储空间迅速扩大,如80386/80486系统的可寻址存储空间达4GB,采用虚拟存储器进一步扩大了程序可访问的存储空间。存储器分页、分段与段页式管理,以及C语言等高级语言程序设计等都要求灵活、高效的扩展寻址方式。下面简叙Pentium微机系统常用的几种扩展寻址方式。
操作数在段内的有效地址由变址寄存器内容乘以比例因子后再加上8/16/32位的位移量。
例如:
IMUL EAX,TAB[ESI*5],11 ; 乘法:EAX←[ESI*5+TAB]*11
MOV ECX,COUNT[EDI+12] ; 传送:ECX←[EDI+12+COUNT]
操作数在段内的有效地址由变址寄存器内容乘以比例因子后再加上基址寄存器内容。
例如:
ADD EAX,[ESI*8][BX] ; 加法:EAX←EAX+[ESI*8+BX]
MOV EDX,[EDI*5][EBP] ; 传送:EDX←[EDI*5+EBP]
操作数在段内的有效地址由变址寄存器内容乘以比例因子,再加上基址寄存器内容和8/16/32位的位移量。
例如:
SUB EDX,LOCA[ESI+20][EBX] ; 减法:EDX←EDX-[ESI+20+EBX+LOCA]
MOV EAX,BUFF[EDI+5][EBX] ; 传送:EAX←[EDI+5+EBX+BUFF]
在32位微机系统中,寻址的地址量都已扩展成32位,通用寄存器也已扩展到32位,但段寄存器仍是16位;在保护方式下,段寄存器是段描述符(8个字节长)的索引号,段描述符中的4个字节表示32位的段基址。
(1)直接寻址。指令中用8位无符号数直接表示I/O端口地址号。
例如:
IN AL,n ; 输入:AL←[n],n在0~255之间,表示端口号
(2)间接寻址。DX指向I/O端口,即用DX内容(16位无符号数)表示I/O端口地址编号,范围在0~65535之间。
例如:
OUT DX,AL ; 输出:[DX]←AL
在早期的16位PC中,DX间接寻址I/O端口范围在限制在0~1023之间。