购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.1 寻址方式

一条指令通常由操作码和操作数两部分构成,其中的操作码部分指示指令执行什么操作,它在机器中的表示比较简单,只需对每一种类型的操作(如加法、减法等)指定一个二进制代码即可;但指令的操作数部分的表示就要复杂得多,它需提供与操作数或操作数地址有关的信息。由于在程序编写上的需要,大多数情况下,指令中并不直接给出操作数,而是给出存放操作数的地址;有时操作数的存放地址也不直接给出,而是给出计算操作数地址的方法。我们称这种指令中如何提供操作数或操作数地址的方式为寻址方式(Addressing Mode)。

计算机执行程序时,根据指令给出的寻址方式,计算出操作数的地址,然后从该地址中取出操作数进行指令的操作,或者把操作结果送入某一操作数地址中去。

寻址方式分为“数据寻址方式”和“转移地址寻址方式”两种类型。虽然后者是指在程序非顺序执行时如何寻找转移地址的问题,但在方法上与前者并无本质区别,因此也将其归入寻址方式的范畴。

在下面的讨论中,为了说明问题的方便,我们均以数据传送指令中的MOV指令为例进行说明,并按汇编指令格式的规定,称指令中两个操作数左边的一个为“目的操作数”,右边的一个为“源操作数”。一般格式为:“MOV目的,源”,指令的功能是将源操作数的内容传送至目的操作数。

4.1.1 数据寻址方式

1.立即寻址

指令中直接给出操作数,操作数紧跟在操作码之后,作为指令的一部分存放在代码段中,这种寻址方式称为立即寻址(Immediate Addressing)。这样的操作数称为立即数,立即数可以是8位、16位或32位。如果是16位或32位的多字节立即数,则高位字节存放在高地址中,低位字节存放在低地址中。立即寻址方式常用来给寄存器赋初值,并且只能用于源操作数,不能用于目的操作数。

由于操作数可以直接从指令中获得,不需要额外的存储器访问,所以采用这种寻址方式的指令执行速度很快,但它需占用较多的指令字节。

例4.1

     MOV  AL, 34H

该指令中源操作数的寻址方式为立即寻址。指令执行后,AL=34H,立即数34H送入AL寄存器。

例4.2

     MOV  AX, 8726H

该指令中源操作数的寻址方式也为立即寻址。指令执行后,AX=8726H,立即数8726H送入AX寄存器。其中AH中为87H,AL中为26H。图4.1给出了指令的操作情况。

图4.1 例4.2指令的操作情况

如图4.1所示,指令存放在代码段中,OP表示该指令的操作码,紧接其后存放的是16位立即数的低位字节26H,然后是高位字节87H。这里,立即数是指令机器码的一部分。

2.寄存器寻址

操作数在CPU内部的寄存器中,由指令指定寄存器号,这种寻址方式称为寄存器寻址(Register Addressing)。对于8位操作数,寄存器可以是AH、AL、BH、BL、CH、CL、DH和DL;对于16位或32位操作数,寄存器可以是16位或32位的通用寄存器;寄存器也可以是段寄存器,但CS寄存器不能做目的操作数。

采用寄存器寻址方式,占用指令机器码的位数较少,因为寄存器数目远少于存储器单元的数目,所以只需很少的几位代码即可表示。另外,由于指令的整个操作都在CPU内部进行,不需要访问存储器来取得操作数,所以指令执行速度很快。

寄存器寻址方式既可用于源操作数,也可用于目的操作数,还可以两者均采用寄存器寻址方式,如例4.3所示。

例4.3

     MOV  AX, BX

该指令中源操作数和目的操作数的寻址方式均为寄存器寻址。若指令执行前,AX=1234H,BX=5678H,则指令执行后,AX=5678H,BX=5678H。

除上述两种寻址方式外,以下各种寻址方式的操作数都在内存中,通过采用不同的方法求得操作数地址,然后通过访问存储器来取得操作数。

需要说明的是,在下面的讨论中,称操作数的偏移地址为有效地址EA(Effective Address),EA可通过不同的寻址方式得到。注意,有效地址就是偏移地址,即访问的内存单元距段的起始地址之间的字节距离。

3.直接寻址

采用直接寻址(Direct Addressing)方式,指令中直接给出操作数的有效地址,并将其存放于代码段中指令的操作码之后。操作数一般存放在数据段中,但也可存放在数据段以外的其他段中。具体存放在哪一段,应通过指令的“段跨越前缀”来指定。在计算物理地址时应使用相应的段寄存器。

例4.4

     MOV  AX, DS:[3000H]

该指令源操作数的寻址方式为直接寻址,指令中直接给出了操作数的有效地址3000H,对应的段寄存器为DS。如DS=2000H,则源操作数在数据段中的物理地址=2000H×16+3000H=20000H+3000H=23000H,指令的执行情况如图4.2所示。图4.2中,假设23000H单元的内容为10H,23001H单元的内容为20H。指令执行后,AX=2010H,其中AH中为20H,AL中为10H。

图4.2 例4.4指令的执行情况

若操作数在附加段中,则应通过“段跨越前缀”来指定对应的段寄存器为ES,如下所示:

     MOV  AX, ES:[2000H]

该指令还可等效地表示为:

     ES: MOV  AX, [2000H]

需要说明的是,在实际的汇编语言源程序中所看到的直接寻址方式,往往是使用符号地址而不是数值地址,即往往是通过符号地址来实现直接寻址的。例如:

     MOV  AX, VAR

其中,VAR为程序中定义的一个内存变量,它表示存放源操作数的内存单元的符号地址(关于变量的概念,将在第5章具体介绍)。

4.寄存器间接寻址

采用寄存器间接寻址(Register Indirect Addressing)方式,操作数的有效地址在基址寄存器(BX、BP)或变址寄存器(SI、DI)中,而操作数则在存储器中。对于80386及以上CPU,这种寻址方式允许使用任何32位的通用寄存器。

寄存器间接寻址的有效地址EA可表示如下:

EA=32位的通用寄存器(80386及以上CPU可用)

若指令中用来存放有效地址的寄存器是BX、SI、DI、EAX、EBX、ECX、EDX、ESI、EDI,则默认的段寄存器是DS;若使用的寄存器是BP、EBP、ESP,则默认的段寄存器是SS。

例4.5

     MOV  AX, [BX]

该指令源操作数的寻址方式为寄存器间接寻址,指令的功能是“把数据段中以BX的内容为有效地址的字单元的内容传送至AX”。若DS=3000H,BX=1000H,则源操作数的物理地址=3000H×10H+1000H=30000H+1000H=31000H。指令的执行情况如图4.3所示,执行结果为AX=30A0H。

图4.3 例4.5指令的执行情况

指令中也可以通过“段跨越前缀”来取得其他段中的数据。例如指令“MOV AX,ES:[BX]”,其源操作数即取自于附加段中。

这种寻址方式可以方便地用于一维数组或表格的处理,通过执行指令访问一个表项后,只需修改用于间接寻址的寄存器的内容就可访问下一项。

5.寄存器相对寻址

采用寄存器相对寻址(Register Relative Addressing)方式,操作数的有效地址是一个基址寄存器(BX、BP)或变址寄存器(SI、DI)的内容与指令中指定的一个位移量(displacement)之和。对于80386及以上的CPU,这种寻址方式允许使用任何32位通用寄存器。其中的位移量可以是8位、16位或32位(80386及以上CPU)的带符号数。

这种寻址方式的有效地址EA的构成可表示如下:

EA=(32位通用寄存器)+DISP(80386及以上CPU可用)

默认段寄存器的情况与前面寄存器间接寻址方式相同,即若指令中使用的是BP、EBP、ESP,则默认的段寄存器是SS;若使用的是其他通用寄存器,则默认的段寄存器是DS。两种情况都允许使用段跨越前缀。

例4.6

     MOV  AX, [SI+TAB ] (也可表示为"MOV  AX, TAB [SI]")

该指令源操作数的寻址方式为寄存器相对寻址,其中的TAB为符号形式表示的位移量,其值可通过伪指令来定义(详见第5章)。若DS=1000H,SI=2000H,TAB=3000H,则源操作数的有效地址EA=2000H+3000H=5000H,物理地址=10000H+5000H=15000H。指令的执行情况如图4.4所示,执行结果为AX=2165H。

图4.4 例4.6指令的执行情况

寄存器相对寻址方式也可方便地用于一维数组或表格的处理,如可将表格首地址的偏移量设置为TAB,通过修改基址寄存器或变址寄存器的内容即可访问不同的表项。

6.基址变址寻址

采用基址变址寻址(Based Indexed Addressing)方式,操作数的有效地址是一个基址寄存器(BX、BP)和一个变址寄存器(SI、DI)的内容之和。其中的基址寄存器和变址寄存器均由指令指定。对于80386及以上的CPU,还允许使用变址部分除ESP以外的任何两个32位通用寄存器的组合。

默认的段寄存器由所选用的基址寄存器决定。即若使用BP、EBP或ESP,则默认的段寄存器是SS;若使用其他通用寄存器,则默认的段寄存器是DS。两种情况都允许使用段跨越前缀。有效地址EA的构成可表示如下:

对于80386及以上CPU,有效地址EA的构成可表示如下:

例4.7

     MOV  AX, [ BX + SI ] (也可表示为"MOV  AX, [ BX ][ SI ]")

该指令源操作数的寻址方式为基址变址寻址。若DS=2000H,BX=1000H,SI=200H,则源操作数的有效地址EA=1000H+200H=1200H,物理地址=20000H+1200H=21200H,指令的执行情况如图4.5所示。指令的执行结果为AX=5678H。

图4.5 例4.7指令的执行情况

这种寻址方式同样适用于一维数组或表格的处理,可将数组首地址的偏移量放于基址寄存器中,而用变址寄存器来访问数组中的各个元素。由于两个寄存器都可以修改,所以它比上述寄存器相对寻址更加灵活。

7.相对基址变址寻址

采用相对基址变址寻址(Relative Based Indexed Addressing)方式,操作数的有效地址是一个基址寄存器(BX、BP)和一个变址寄存器(SI、DI)的内容与指令中给定的一个位移量(DISP)之和。对于80386及以上的CPU,还允许使用变址部分除ESP以外的任何两个32位通用寄存器及一个位移量的组合。两个寄存器均由指令指定。位移量可以是8位、16位或32位(80386及以上)的带符号数。

默认的段寄存器由所选用的基址寄存器决定。即若使用BP、EBP或ESP,则默认的段寄存器是SS;若使用BX或其他32位通用寄存器,则默认的段寄存器是DS。两种情况都允许使用段跨越前缀。有效地址EA的构成表示如下:

对于80386及以上CPU,有效地址EA的构成可表示如下:

例4.8

     MOV  AX, [ BX + SI + DISP ]
     (也可表示为"MOV AX, DISP [BX][SI]"或"MOV AX, DISP[BX+ SI]")

这种寻址方式可以用于访问二维数组,设数组元素在内存中按行顺序存放(先放第一行所有元素,再放第二行所有元素……),将DISP设为数组起始地址的偏移量,基址寄存器(如BX)为某行首与数组起始地址的字节距离(即BX=行下标×一行所占用的字节数),变址寄存器(如SI)为某列与所在行首的字节距离(对于字节数组,即SI=列下标),这样,通过基址寄存器和变址寄存器即可访问数组中不同行和列上的元素。若保持BX不变而SI改变,则可以访问同一行上的所有元素;若保持SI不变而BX改变,则可以访问同一列上的所有元素。

4.1.2 转移地址寻址方式

一般情况下指令是顺序逐条执行的,但实际上也经常发生执行转移指令改变程序执行流向的现象。与前述数据寻址方式是确定操作数的地址不同,转移地址寻址方式是用来确定转移指令的转向地址(又称转移的目标地址)。下面首先说明与程序转移有关的几个基本概念,然后介绍4种不同类型的转移地址寻址方式,即段内直接寻址、段内间接寻址、段间直接寻址和段间间接寻址。

如果转向地址与转移指令在同一个代码段中,这样的转移称为段内转移,也称近转移;

如果转向地址与转移指令位于不同的代码段中,这样的转移称为段间转移,也称远转移。近转移时的转移地址只包含偏移地址部分,找到转移地址后,将其送入IP即可实现转移(不需改变CS的内容);远转移时的转移地址既包含偏移地址部分又包含段基值部分,找到转移地址后,将转移地址的段基值部分送入CS,偏移地址部分送入IP,即可实现转移。

如果转向地址直接放在指令中,则这样的转移称为直接转移,视转移地址是绝对地址还是相对地址(即地址位移量)又可分别称为绝对转移和相对转移;如果转向地址间接放在其他地方(如寄存器中或内存单元中),则这样的转移称为间接转移。

1.段内直接寻址

采用段内直接寻址(Intrasegment Direct Addressing)方式,在汇编指令中直接给出转移的目标地址(通常是以符号地址的形式给出);而在指令的机器码表示中,此转移地址是以对当前IP值的8位或16位位移量的形式来表示的。此位移量即为转移的目标地址与当前IP值之差(用补码表示);指令执行时,转向的有效地址是当前的IP值与机器码指令中给定的8位或16位位移量之和。

段内直接寻址方式既适用于条件转移指令也适用于无条件转移指令,但当它用于条件转移指令时,位移量只允许8位;无条件转移指令的位移量可以为8位,也可以为16位。通常称位移量为8位的转移为“短转移”。

段内直接寻址转移指令的汇编格式如例4.9所示。

例4.9

     JMP  NEAR PTR  PROG1
     JMP  SHORT  LAB

其中,PROG1和LAB均为符号形式的转移目标地址。在机器码指令中,它们是用距当前IP值的位移量的形式来表示的。若在符号地址前加操作符“NEAR PTR”,则相应的位移量为16位,可实现距当前IP值-32768~+32767字节范围内的转移;若在符号地址前加操作符“SHORT”,则相应的位移量为8位,可实现距当前IP值-128~+127字节范围内的转移。若在符号地址前不加任何操作符,则默认为“NEAR PTR”。

2.段内间接寻址

采用段内间接寻址(Intrasegment Indirect Addressing)方式,转向的有效地址在一个寄存器或内存单元中,其寄存器号或内存单元地址可用数据寻址方式中除立即寻址以外的任何一种寻址方式获得。转移指令执行时,从寄存器或内存单元中取出有效地址送给IP,从而实现转移。

段内间接寻址转移指令的汇编格式如例4.10所示。

例4.10

     JMP  BX
     JMP  WORD PTR [BX+SI]

第一条指令JMP BX执行时,将从寄存器BX中取出有效地址送入IP。

第二条指令中的操作符“WORD PTR”表示其后的[BX+SI]是一个字型内存单元。指令执行时,将从[BX+SI]所指向的字单元中取出有效地址送入IP。

3.段间直接寻址

采用段间直接寻址(Intersegment Direct Addressing)方式,指令中直接提供转向地址的段基值和偏移地址,所以只要用指令中指定的偏移地址取代IP的内容,用段基值取代CS的内容就完成了从一个段到另一个段的转移操作。

这种指令的汇编格式如下所示:

     JMP  FAR PTR  LAB

其中,LAB为转向的符号地址,FAR PTR则是段间转移的操作符。

4.段间间接寻址

采用段间间接寻址(Intersegment Indirect Addressing)方式,用存储器中的二个相继字单元的内容来取代IP和CS的内容,以达到段间转移的目的。其存储单元的地址是通过指令中指定的除立即寻址和寄存器寻址以外的任何一种数据寻址方式取得的。

这种指令的汇编格式如下所示:

     JMP  DWORD PTR [BX+SI]

其中,[BX+SI]表明存储单元的寻址方式为基址变址寻址,“DWORD PTR”为双字操作符,说明要从存储器中取出双字的内容来实现段间间接转移。 gnVhKTpRjV/74vM9HgWh/QHFEgtiNRal7LEqh2SBdj7VpF6um0Ga81TDBR4LjUPG

点击中间区域
呼出菜单
上一章
目录
下一章
×