寻址模式
寻址模式(Addressing modes)是中央处理器(CPU)设计中,指令集架构的一部分。各个指令有不同的寻址模式,这些寻址模式决定此架构下的机器语言指令对应的运算数。寻址模式会通过暂存器中的数值或机器指令中的常数来计算运算数的记忆体位址。
在计算机程序设计中,寻址模式主要是汇编语言使用者和编译器编写者需要关注的。对于一个相关的概念,请参阅正交指令集,它涉及到任何指令使用任何寻址模式的能力。
警告
注意,各种寻址模式都没有一个被普遍接受的的名称。不同的作者和计算机制造商可以为相同的寻址模式赋予不同的名称,或者为不同的寻址模式赋予相同的名称。
术语“寻址模式”本身也有不同的解释:可以解释为“存储器地址计算方式”,也可以解释为“操作数访问方式”。 在第一种解释下,不从存储器读取或写入存储器的指令(例如“将立即数放入寄存器”)被认为没有“寻址模式”。 第二种解释允许诸如VAX的机器使用立即数模式位来允许寄存器或立即数。 只有第一种解释适用于诸如“加载有效地址”之类的指令。
下面列出的寻址模式分为代码寻址和数据寻址。 大多数计算机体系结构都保持这种区别,但是存在一些允许在(几乎)任何上下文中使用任何寻址模式使用的体系结构。
下面的说明纯粹具有代表性,以说明寻址模式,并不一定反映任何特定计算机使用的助记符。
寻址模式的数量
不同的计算机体系结构在硬件中提供的寻址模式数量上有很大差异。 消除复杂寻址模式并仅使用一个或几个更简单的寻址模式有一些好处,即使它需要一些额外的指令,也许还需要一个额外的寄存器。 如果只有一些简单的寻址模式,那么设计管流水线CPU将变得更为简单。
大多数RISC架构只有大约五种简单的寻址模式,而DECCAX等CISC架构有十几种寻址模式,其中一些非常复杂。 IBM System/360架构只有三种寻址模式,System/390又添加了一些。
当只有少数寻址模式时,所需的特定寻址模式通常在指令代码中编码(例如IBM System/360和后继者,还有大多数RISC)。 但是当存在许多寻址模式时,通常在指令中留出特定字段来指定寻址模式。 DEC VAX允许几乎所有指令有多个存储器操作数,因此保留每个操作数说明符的前几位以指示该特定操作数的寻址模式。 保持寻址模式指定符位与操作码操作位分离产生正交指令集 。
即使在具有许多寻址模式的计算机上,实际程序的测量表明下面列出的简单寻址模式占所有寻址模式的约90%或更多。 由于大多数此类测量基于编译器从高级语言生成的代码,因此这在某种程度上反映了所使用的编译器的局限性。
对代码的寻址模式
绝对寻址/直接寻址
+----+------------------------------+ |jump| address | +----+------------------------------+ (有效PC位址 = address)
绝对寻址指令的有效地址是地址参数本身,无需修改。
PC相对寻址
+----+------------------------------+ |jump| offset | 相对跳转指令 +----+------------------------------+ (有效PC位址 = 下一條指令的位址 + offset,offset 可為負數)
PC对寻址的有效地址是下一条指令地址加上偏移参数。 通常对该偏移是有符号数,以允许跳转到指令之前和之后的代码。
这种寻址方式的跳转指令特别有用,因为常见的跳转指令的目标是是附近的指令(在高级语言中,大多数if或while语句相当短)。 实际程序的测量表明,对于大约90%的条件跳转(大约±128或±512字节),8或10位偏移就足够了。
PC相对寻址的另一个优点是代码可以是位置无关的 ,即它可以加载到存储器中的任何地方而无需调整任何地址。
这种寻址模式的某些版本可以是有条件的,这些条件例如两个寄存器之间的关系:“如果reg1 = reg2跳转”、一个寄存器自身:“跳转除非reg1 = 0”或者隐含地状态寄存器中某些位。
寄存器间接寻址
+-------+-----+ |jumpVia| reg | +-------+-----+ (有效PC位址 = 'reg'中的值)
对数据的寻址模式
寄存器(直接)寻址
+------+-----+-----+-----+ | mul | reg1| reg2| reg3| reg1 := reg2 * reg3; +------+-----+-----+-----+
这种“寻址模式”没有有效地址,在某些计算机上不被认为是寻址模式。
在此示例中,所有操作数都在寄存器中,结果放在寄存器中。
基址加偏移量寻址,及其变种
有时被称为“偏移寻址”
+------+-----+-----+----------------+ | load | reg | base| offset | reg := RAM[base + offset] +------+-----+-----+----------------+ (有效地址 = offset + base 寄存器的内容)
立即数/字面量寻址
+------+-----+-----+----------------+ | add | reg1| reg2| constant | reg1 := reg2 + constant; +------+-----+-----+----------------+
这种“寻址模式”没有有效地址,并且在某些计算机上不被认为是寻址模式。
常量可以是有符号或无符号的。 例如, move.l #$FEEDABBA, D0
将十六进制值“FEEDABBA”值移动到寄存器D0中。
操作数的值保存在指令本身中,而不是使用内存中的操作数。
隐含寻址
隐含寻址模式(在X86汇编语言中也称为隐式寻址模式)未明确指定源和/或目标的有效地址。
操作码隐含源(如果有)或目的地有效地址(或有时两者)。
隐含的寻址在较旧的计算机上很常见(直到20世纪70年代中期)。 这样的计算机通常只有一个寄存器,可以在其中执行算术-累加器。 这种累加器机器几乎在每个指令中都隐含地引用了累加器。 例如,操作
a:= b + c;
可以使用序列
load b; add c; store a;
“load”和“add”指令都隐含目的寄存器(累加器); 每个“store”指令都隐含了源寄存器(累加器)。
后来的计算机通常具有多个通用寄存器,它们可以是算术的源寄存器和/或目的寄存器,因此后来的计算机需要一些其他寻址模式来指定算术的源寄存器和目的寄存器。