第3章 指令格式与寻址方式

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第3章指令格式与寻址方式
【本章内容提要】本章讲述Intel系列微处理器的指令通用格式和各种寻址方式。

除无操作数指令以外,一般指令都需要指出操作数,指令中操作数的给出(即寻址方式)有多种方法。

通过多种寻址方式,提高了程序设计的灵活性,也扩充了指令的具体功能。

【本章学习目标】
●熟练掌握汇编语言指令和机器指令的基本格式
●明确操作数的各种寻址方式
●掌握各种寻址方式物理地址的计算
3.1 指令格式
机器指令一般由操作码和操作数组成。

操作码指示指令所要完成的操作,如加法、减法、数据传送等,它是指令中必不可少的部分;操作数指示指令执行过程中所需要的数据,如加法指令中的加数、被加数等,这些数据可以是操作数本身,也可以来自某寄存器或存储器单元,一条Intel机器指令可以有零到三个操作数。

汇编语言指令与机器指令是一一对应的。

汇编语言指令的一般格式为:
指令助记符操作数列表;注释
格式说明:
①指令助记符表示指令的名称,一般是指令功能的英文缩写,对应的是机器指令中的操作码部分,也是一条指令中必不可少的部分;
②若指令中包含多个操作数,则操作数之间以逗号(,)分隔。

一般来说,将存放操作结果的操作数称为目的操作数,大多是指令的第一个操作数。

其他操作数称为源操作数,其值在指令执行后保持不变。

但有的单操作数指令中的操作数既是源操作数又是目的操作数,还有的指令无需明确指出操作数,成为无操作数指令;
③注释以分号(;)开始,用来说明程序功能,不影响指令的执行。

【例】 INC AX ;单操作数指令,把AX寄存器的内容加1
MOV EAX,[1000H] ;双操作数指令,将1000H号内存的32位数据传送给EAX
IMUL RAX,R8,100 ;三操作数指令,将R8寄存器与100的乘积保存到RAX寄存器
HLT ;无操作数指令,完成停机功能
这个例子通过具体指令给出了汇编语言指令的基本格式,指令相应的功能将在本章后续内容中详细叙述。

指令的一个操作数可以是立即数、寄存器或者内存单元,然而指令中操作数的给出方式却是多样的,比较灵活。

为了明确具体操作数的存在位置,必须首先要明确操作数的寻址方式。

3.2 操作数类型和有效地址
指令中所使用的操作数不光是有多种寻址方式,而且操作数本身也是有多种类型的。

汇编语言程序设计14 3.2.1 操作数类型
一般指令中可以有4种类型的操作数,它们分别对应了四种可能的存放位置:
1)操作数包含在指令中,即指令的操作数部分就是操作数本身(立即数),这种操作数寻址方式称为立即寻址。

而且立即数只能作为源操作数。

2)操作数包含在CPU的某个内部寄存器中。

这时指令的操作数部分是CPU内部寄存器的一个编码,这种操作数寻址方式称为寄存器寻址。

3)操作数在内存的数据区中。

这时指令的操作数部分包含着此操作数所在的内存地址,这种操作数寻址方式称为存储器寻址。

4)操作数在外部设备端口中。

这种情况只适用于输入输出指令,根据外部设备的端口号完成数据的输入或输出,称为端口寻址。

对于立即寻址和寄存器寻址,由于操作数已经在CPU内部了,无需再访问内存,所以指令执行周期相对较短。

对于存储器寻址,操作数所在的内存地址的给出有多种形式,以适应多种不同的数据类型应用,所以必须首先明确有效地址的概念。

对于端口寻址,由于要访问外部I/O设备,一般来说指令执行周期相对较长。

3.2.2 有效地址
在IA-32及Intel64系列CPU中,任何内存单元的地址都是由两部分组成:段基地址和段内偏移地址(也称段内偏移量)。

存储器寻址时,指令的操作数部分给出的地址就是这个段内偏移量。

在实际应用中所用到的数据类型可能是多种多样的,为了适应要处理的各种数据结构的需要,这个段内偏移量最多可以由四个基本部分(称为有效地址四分量),按照一定的规则计算组合而成,所以也把段内偏移量称为有效地址EA。

有效地址四个分量具体包括:①基址寄存器内容;②变址寄存器内容;③比例因子;
④位移量。

其中,基址、变址寄存器的值通常为某局部存储区的首地址(比如数组);比例因子是32位和64位寻址方式中用到的;位移量是一般是一个具体数值。

由这四种分量可组合出多种存储器寻址方式。

它们的组合情况和计算方法如下:
EA=[基址寄存器]+([变址寄存器]×比例因子)+位移量
对于不同位数方式的操作数寻址,有效地址四种分量的使用规则有所不同,表3.1给出了这各种存储器寻址时四种分量使用规则的区别。

表3.1 有效地址四分量的使用规则
16位寻址方式主要是针对于实地址存储模式的应用,兼容了Intel 8086的工作模式。

存储器的最大分段不超过64KB,最大线性地址空间是1MB。

32位寻址方式主要是用于保护模式下,程序只能存取最低4GB地址空间,使用16位或32位地址。

使用16位的分段选择子以及32位的段内偏移地址,每个段最大可达4GB。

64位寻址方式采用64位线性地址空间,支持40位物理地址空间。

通常不采用分段方
第3章 指令格式与寻址方式 15
式,而是将CS ,DS ,ES 和SS 的段基址看成0,这样线性地址等于有效地址,是一种平展存储管理模式。

Intel 扩展存储器64位技术(EM64T ),使得具有64位指令系统的CPU ,既可以以兼容方式在64位操作系统下运行32位传统软件而无需修改和重新编译,也可以运行访问64位地址空间的应用程序。

3.3 各种寻址方式
IA-32及Intel64系列CPU 的指令操作数寻址方式可分为4大类,共有11种不同的情况。

对8086/8088CPU 来说只有其中8种,都是16位寻址的,目前主要是运行在实地址方式或V86方式下的兼容应用。

凡指令中涉及32位寻址的均对32位CPU 而言,涉及64位寻址的均对具有64位指令系统的CPU 而言。

以下介绍中均以指令的源操作数为例进行分析。

3.3.1 立即寻址
立即寻址方式下,操作数作为立即数直接包含在指令中,它紧跟在操作码之后与其一起存放在代码段区域。

因而立即数总是和操作码一起被取入CPU 的指令队列,在指令执行时不需再访问存储器。

立即操作数可以是8位、16位、32位或64位的。

若是16位的,则低位字节存放在相邻两个字节存储单元的低地址单元中;若是32位的,则低位字存放在相邻两个字存储单元的低地址单元中;若是64位的,则和32位数据存储类同。

立即寻址方式仅用于源操作数,而不能作目的操作数,主要用于给寄存器赋初值。

【例3.1】MOV BL ,12H ;字节传送
MOV AX ,1020H ;16位传送
MOV EDX ,12345678H ;32位传送
MOV RAX ,1122334455667788H ;64位传送 其中MOV AX ,1020H 的执行过程如图3.1所示。

指令源操作数是1020H ,目标操作数是AX ,指令的功能是把立即数1020H 传送到寄存器AX 。

在64位模式下,只有MOV 指令允许使用64位立即数,其他指令只能使用不超过32位的立即数。

3.3.2 寄存器寻址
在寄存器寻址方式下,被访问的操作数存放在指令规定的8位、16位、32位或64位
图3.1 立即寻址方式示意图 图3.2 寄存器寻址方式示意图
汇编语言程序设计16 寄存器中。

【例3.2】INC CL ;8位寄存器加1
MOV DS,AX ;16位寄存器传送
MOV ECX,EAX ;32位寄存器传送
MOV RBX,RAX ;64位寄存器传送
其中MOV DS,AX 的执行过程如图3.2所示。

因为寄存器存在于CPU内部,在寄存器寻址方式下CPU执行指令时,不需要使用访问总线,所以指令的执行速度快。

在某些特殊的指令中有的操作数不需要指出,而是隐含在某些特定的寄存器中,如乘法指令,这种寻址方式也可以称为隐含寻址。

3.3.3 存储器寻址
对各种存储器寻址方式:操作数都是在存储区中,指令的操作数部分指出此操作数的有效地址EA。

根据EA的生成方式的不同,可分为以下几种寻址分式。

(1)直接寻址
称,是最简单的一种存储器寻址方式。

这种寻址方式下,指令中的操作数部分
直接给出操作数的有效地址EA,是16
位或32位的位移量数据,它与操作码一
起放在代码段中。

操作数一般在数据段
(DS)中,这是一种默认方式。

如果要
对除DS段之外的其它段(CS、ES、SS、
FS、GS)中的数据寻址,应在指令中增
加前缀指出段寄存器名,这称为段超越。

【例3.3】 MOV AX,[2000H] ;将DS段中2000H和2001H单元内容分别送AL和AH
MOV AX,ES:[2000H] ;将ES段中2000H和2001H单元内容分别送AL和AH 图3.3以指令MOV AX,[2000H]给出了直接寻址方式示例。

需要注意的是,存储器操作数的高位字节对应高地址,低位字节对应低地址。

在该指令中指出的2000H内存单元为低地址,其中存放的内容(34H)为操作数的低字节,应该传送给AL,而2001H内存单元为高地址,其中存放的内容(12H)为操作数的高字节,应该传送给AH。

直接寻址中的存储器操作数的有效地址EA也可以用变量名的形式给出。

【例3.4】 VALUE DB 10H
MOV AL,VALUE ;将变量名为VALUE中的数据10H存入AL
(2)寄存器间接寻址
操作数在存储器中,而操作数的有效地址EA却在指定的寄存器中,即
EA=[寄存器]
对于寄存器的使用规定在16位寻址和32位寻址时也不一样:
1)16位寻址时,EA放在SI、DI、BP或BX中。

这时又有两种段默认情况:
·若以SI、DI、BX间接寻址,则默认操作数在DS段中。

【例3.5】MOV AX,[SI] ;默认DS为段基址
第3章指令格式与寻址方式17 ·若以寄存器BP间接寻址,则默认操作数在堆栈段中。

【例3.6】MOV AX,[BP] ;默认SS为段基址
如果操作数不在上述规定的默认段,则必须在指令中相应的操作数前加上段超越前缀。

【例3.7】MOV CX,DS:[BP] ;“DS:”是段超越前缀,表示访问数据段,而非堆栈段
2)32位寻址时,8个32位通用寄存器均可作寄存器间接寻址使用。

【例3.8】MOV CH,[EAX]
MOV DX,[EBX]
这时,除EBP、ESP默认段寄存器为SS外,其余6个寄存器均默认段寄存器DS。

同样可以采用加段超越前缀的方法对其它段进行寻址。

但要注意的是,CS和ES不能被超越,在堆栈操作时,SS也不能被超越。

指令MOV AX,[BX] 的执行过程如图3.4所示:假设BX寄存器的内容为1000H,则把DS段中的1000H号单元的16位数据传送给AX寄存器,该指令的机器码为8B07H。

直接寻址中有效地址EA来自指令自身,相当于一个常量;而寄存器间接寻址中有效地址EA来自寄存器,该内容由前面的指令确定,相当于一个变量。

这就是两种寻址方式的区别。

3)64位寻址时,16个32位/64位通用寄存器均可作寄存器间接寻址使用。

【例3.9】 MOV CL,[R10] ;操作数是8位的,操作数地址由64位寄存器R10指出
MOV RDX,[EBX];操作数是64位的,操作数地址由32位寄存器EBX指出,经零扩
;展后形成64位有效地址
(3)寄存器相对寻址
在寄存器寻址方式下,操作数的有效地址为:
EA=[基址寄存器或变址寄存器]+位移量
其中位移量由指令直接给出,是指令的一部分。

基址或变址寄存器的使用规则如下:1)16位寻址时,BP和BX作为基址或变址寄存器,默认情况下,BX以DS作为段寄存器,BP以SS作为段寄存器;SI(源变址)和DI(目的变址)作为变址寄存器,默认DS作为段基址寄存器。

位移量是8位或16位。

2)32位寻址时,8个32位通用寄存器都能作为基址或变址寄存器。

其中ESP、EBP 默认段寄存器为SS,其余6个寄存器均默认段寄存器为DS,段可以超越;除ESP外的任何32位通用寄存器均可作变址寄存器。

且EBP以SS为默认段寄存器,其余以DS为默认段寄存器。

位移量是8位或32位,当位移量超过8位则按照32位处理。

【例3.10】 MOV AX,[SI+24] ;也可写成 MOV AX,24[SI]
汇编语言程序设计18 MOV ECX,[EBP+50] ;也可写成 MOV ECX,50[EBP]
MOV DX,[EAX+BASE] ;也可写成 MOV DX,BASE[EAX];BASE是符号常量或变量
图3.5给出了寄存器相对寻址的执行过程示例,MOV ECX,[EBP+50]指令执行时,EBP寄存器内容为3000H,再加上位移量50H之和为3050H,然后把由SS寄存器寻址的段中的3050H单元的32位数据传送给ECX。

3)64位寻址时,16个32位/64位通用寄存器都能作为基址寄存器。

当使用32位通用寄存器时,先将32位通用寄存器内容零扩展为64位,再与经过符号扩展为64位的位移量相加形成64位有效地址。

只有MOV指令允许使用64位的位移量,而其他指令只能使用不超过32位的位移量。

【例3.11】MOV RAX,[R15+5] ;有效地址为R15寄存器内容加5 的和
MOV RCX,[EDX+0F0H];有效地址为EDX寄存器内容零扩展为64位后,再与位移量
;0F0H符号扩展成64位(0FFFFFFFFFFFFFFF0H)相加的和寄存器相对寻址非常适于对一维数组素进行检索操作。

比如要检索字节数组ARRAY 的第5个元素,用指令“MOV ECX,ARRAY[EAX]”,可以使位移量等于ARRAY数组起始地址的偏移量,数组元素的下标5存放在寄存器EAX中,这样指令不变,只修改基址或变址寄存器的内容就可以访问数组中的任意元素了。

(4)基址加变址寻址
在这种寻址方式中,操作数的有效地址EA=[基址寄存器]+[变址寄存器]。

寄存器的使用方法与前面所述相同。

比较特别的是,当一种寻址方式中基址、变址寄存器默认的段寄存器不同时,一般由基址寄存器来决定默认哪一个段寄存器作段基址。

也可以在指令中规定段超越,来选择其它段寄存器作为段基地址。

【例3.12】MOV AX,[BX+SI] ;或写成MOV AX,[BX][SI],BX决定默认段基址由DS指出 MOV EAX,[EDX][EBP] ;由EBP决定默认SS为段基址寄存器
MOV R12,[EAX+EDX] ;用于64位方式,有效地址为EAX+EDX的和再扩展为64位
MOV RBX,[R10+RBP] ;有效地址为R10+RBP的64位和。

第3章指令格式与寻址方式19
图3.6给出了基址加变址寻址的执行过程示例,假设BX=2000H,SI=3000H,那么指令MOV AX,[BX][SI]的功能是把5000H单元的16位数据传送到AX。

基址加变址寻址很适合于检索二维数组元素和双重循环等任务。

需要注意的是,在16位方式下,只能用基址寄存器(BX或BP)之一与变址寄存器(SI或DI)之一相加形成有效地址,而不能同时用BX和BP或者同时用SI和DI寄存器。

(5)带位移的基址加变址寻址
在这种寻址方式下,有效地址为:
EA=[基址寄存器]+[变址寄存器]+位移量
该寻址方式对于16位、32位和64位方式都适合。

基址、变址寄存器的使用规定和对段寄存器的默认规定与前面所述相同。

【例3.13】MOV AX,[BX+SI+SOME] ;或MOV AX,MASK[BX][SI] 16位寻址
MOV EAX,[EBX+EBP+2] ;32位寻址
MOV R8,[R9+R10+4] ;64位寻址
(6)比例变址寻址
这种寻址方式只适于32位或64位寻址的情况。

有效地址为:
EA=[变址寄存器]×比例因子+位移量
乘比例因子的操作是在CPU内部靠硬件完成的。

【例3.14】MOV EAX,ARRAY[ESI×4] ;32位寻址
MOV RAX,[RBX×8+10H] ;64位寻址
比例变址寻址的作用和寄存器寻址的作用相似,但更适用于对多字节一维数组元素进行检索。

比如要检索32位数组ARRAY的第10个元素,结果存放到EAX中,可以使位移量等于ARRAY数组起始地址的偏移量,数组元素的下标10存放在变址寄存器ESI中,用指令MOV EAX,ARRAY[ESI×4]来实现。

(7)基址加比例变址寻址
这种寻址方式只适于32位或64位寻址的情况,有效地址为:
EA=[基址寄存器]+[变址寄存器]×比例因子
【例3.15】MOV EDX,[EAX×2][EBX] ;或 MOV EDX,[EAX×2+EBX]
MOV EAX,[EBX×4][ESI] ;或 MOV EAX,[EBX×4+ESI]
MOV RBX,[RAX×4+RCX] ;只适用于64位方式
在检索多字节二维数组元素时可以用这种寻址方式。

(8)带位移的基址加比例变址寻址
汇编语言程序设计20 这种寻址方式将有效地址的全部四个分量,是最复杂的寻址方式。

在这种寻址方式下有效地址为:
EA=[基址寄存器]+[变址寄存器]×比例因子+位移量
该寻址方式用到了比例因子,只能是32位或64位寻址。

各种规定和默认情况同前所述。

寻址过程中,变址寄存器内容乘以比例因子的操作在CPU内部由硬件完成。

【例3.16】 MOV AX,[EBX×8+ECX+100] ;或 MOV AX,[EBX×8][ECX+100]
如果二维数组的数组元素大小为8字节,数组起始地址为100时,把数组某行的起始地址保存在ECX中,数组列号保存在EBX中,上述指令即把当前元素传送到AX寄存器。

3.3.4 端口寻址
端口寻址方式只在对外部设备的访问指令中适用,包括端口的直接寻址和间接寻址两种方式,具体细节在4.4.5节的I/O数据传送类指令的叙述中,结合具体指令详细介绍。

以上对操作数的4大类共11种寻址方式都进行了具体叙述,充分利用各种寻址方式的特点,可以使指令或程序的执行更加灵活方便,进而提高效率。

另外,在某些指令中对操作数有隐含的使用约定,称为隐含寻址,比如3.3节中介绍的乘除法指令以及某些堆栈操作指令都有隐含的寄存器使用约定。

存储器操作数的寻址方式是最复杂的,访问存储器时,除了要计算有效地址EA外,还必须确定操作数所在的段,即确定有关的段寄存器。

一般情况下,程序(即指令代码)只能在代码段中;堆栈操作数只能在堆栈段中;目的串操作数只能在附加数据段中。

其它操作都可以按如前所述的默认段处理,也允许使用段超越方式访问。

段寄存器的使用规则如表3.2所示。

表3.2 存储器寻址时寄存器的使用规则
以上叙述主要适用于16位或32位寻址的情况。

对于64位方式下,由于采用平展存储器地址管理模式,基本不用分段和实地址模型。

对寄存器的使用也有所限制,即指令不能同时访问以下组1中和组2中所列出的寄存器。

组1包括AH、BH、CH和DH;组2包括SIL、DIL、SPL、BPL和R8L~R15L。

例如指令MOV AH,R8L或者MOV BH,SIL,这两条指令的操作数都是分别来自组1和组2,都是非法应用。

在64位地址方式下,操作数宽度默认的是32位,如果要访问64位操作数,或者是指令要用到新的扩展寄存器的情况下,汇编指令生成机器代码时会加入一个64位指令特有的前缀REX。

REX前缀占一个字节,其中高4位固定为0100,低4位分别用WRXB表示,所以其代码为40H~4FH。

W位(即REX.W位)如果为1则表示操作数是64位的;
第3章指令格式与寻址方式21 如果W位为0则表示操作数的位数(16或32位)由代码段描述符确定。

例如指令“ADD EAX,10H”的机器代码为:83 C0 10;而指令“ADD RAX,10H”的机器代码则为:48 83 C0 10。

就是因为后者用到了64位操作数,必须加入一个REX前缀字节明确指出。

REX前缀的最低3位(RXB)是64位寻址方式的扩展位。

非64位方式下只有8个通用寄存器,只需3位表达式即可编码,而现在要用到16个通用寄存器了,必须要用4位编码才行。

REX.R位主要用于和原来寻址方式字段中的3位(MOD R/M)组合实现16个通用寄存器的寻址,REX.X和REX.B则主要用于和原来寻址方式字段中的相应3位编码组合,分别实现16个寄存器的变址寻址和基址寻址方式的编码。

需要强调的是,64位方式下并不是所有的指令都需要REX前缀,如果需要,每条指令也只能有一个REX前缀。

在32位方式下,64位通用寄存器的高32位没有定义。

如果从64位工作方式切换到32位保护方式或兼容方式,则64位通用寄存器的高32位将不被保存,所以软件不能依靠这些信息作下一步处理。

另外在64位方式下,目标通用寄存器的有效位数是由操作数的宽度决定的:
•64位操作数生成64位有效结果;
•32位操作数生成32位结果,然后零扩展成64位再保存至目标通用寄存器中;
•8位或16位操作数生成8位或16位结果,但不修改目标通用寄存器的高56位或48位,然而如果8位或16位的操作结果是用于64位地址计算的,则应该明确地将操作结果符号扩展成64位。

习题3
3.1 访问内存单元的寻址方式有几种?它们具体是哪些?
3.2 指出下列各种操作数的寻址方式。

1)[BX] 2)SI
3)435H 4)[BP+DI+123]
5)[23] 6)data (data是一个内存变量名)
7)[DI+32] 8)[BX+SI]
9)[EAX+90] 10)[BP+4]
3.3 哪些寄存器的值可用于表示内存单元的偏移量?
3.4 判断下列操作数的寻址方式的正确性,对正确的指出其寻址方式,对错误的说明其错误原因。

1)[AX] 2)[EAX] 3)BP
4)[SI+DI] 5)DS 6)BH
7)[BX+BP+32] 8)[BL+44] 9)[CX+90]
10)EDX 11)BX+90H 12)[DX]
13)SI[100h] 14)[BX*4] 15)[EAX+EBX*6]
3.5 已知寄存器EBX、DI和BP的值分别为12345H、0FFF0H和42H,试分别计算出下列各操作数
的有效地址。

1)[BX] 2)[DI+123H]
3)[BP+DI] 4)[BX+DI+200H]
5)[1234H] 6)[EBX*2+345H]
3.6 指出下列各寻址方式所使用的段寄存器。

1)[SI+34h] 2)[456H]
3)ES:[BP+DI] 4)[BX+DI+200H]
5)[BP+1234H] 6)FS:[EBX*2+345H]。

相关文档
最新文档