常见的数据寻址方式

十种寻址方式,看上去要背十条公式。但它们其实只回答同一个问题:指令里那个装不下完整地址的形式地址 ,要配上什么才能凑出有效地址 EA。

按”配什么”来分,十种立刻塌缩成四组:

配什么有哪几种
什么都不配( 本身就够)隐含、立即、直接、寄存器
再访存一次(拿 指的内容当地址)间接、寄存器间接
加一个寄存器(某寄存器)相对、基址、变址 ←偏移寻址三兄弟
由 SP 隐含堆栈

第三组三种的公式一模一样,是本节全部难点所在,本页会用一整节把它们拆开。

机制

十种寻址方式总表

寻址方式有效地址 EA取操作数访存次数特点
隐含寻址隐含在操作码中0 或 1缩短指令字长(如 ACC)
立即寻址无—— 就是操作数本身0最快,但数的范围受 位数限制
直接寻址1简单,但寻址范围只有 ( 为形式地址位数)
间接寻址2(多级则 )寻址范围大、便于子程序返回;慢
寄存器寻址,操作数在寄存器0快、指令短
寄存器间接寻址1比间接寻址少一次访存
相对寻址1程序浮动、段内转移
基址寻址1程序重定位、多道程序
变址寻址1数组、循环
堆栈寻址 栈顶(SP 隐含)0(硬堆栈)/ 1(软堆栈)后进先出

立即寻址的 是补码,所以它的表示范围是 而不是 ——这是选择题里的常见细节。

访存次数模板

一道题要么问”共访存几次”,要么问”取操作数访存几次”,两者差一个取指,读题时先圈出来。

总访存次数指令字长存储字长取指取操作数看上表存结果或

四步走:

  1. 取指几次:指令字长 ÷ 存储字长(4.1.2)
  2. 每个源操作数几次:查上表,间接寻址每多一级多一次
  3. 结果要不要写回主存:写回寄存器/ACC 是 0 次,写回主存是 1 次(且写回地址若也是间接寻址,要再加)
  4. 加起来

例 单字长指令、存储字长等于指令字长。ADD @A 是一地址读改写指令, 采用一次间接寻址,结果存回原处。 取指 1 + 取 EA 1 + 取操作数 1 + 存结果 1 = 4 次。 若改成直接寻址,则 1+1+1 = 3 次。

间接寻址:慢,但换来两样别的方式给不了的东西

要多访存一次,多级间接更是每级一次,为什么还留着它?

  1. 突破形式地址的位数限制: 只有 8 位,但 指向的那个主存单元有 32 位——一个 8 位字段间接寻遍 4 GB。
  2. 地址可以在运行时改:指令本身是只读的,但 指向的那个单元可以随时改内容。这是子程序返回、跳转表、函数指针的实现基础,也是 switch 语句编译成跳转表时用的方式(见 4.3.2)。

多级间接需要在被指向的字上留一位标志,说明”这还是个地址,请继续”。所以一个 32 位字里往往只有 31 位是地址。这一条偶尔考。

偏移寻址三兄弟:公式相同,差别在”哪一半是变量”

三者的 EA 都是 某寄存器内容 + 形式地址 ,加法电路完全相同。它们不是三种硬件,是同一种硬件的三种用法。

相对寻址基址寻址变址寻址
基准寄存器PC基址寄存器 BR变址寄存器 IX
寄存器内容由谁定硬件自动(取指时更新)操作系统 / 装入程序用户程序
执行期间寄存器变吗随取指自动变不变不断变
执行期间 变吗不变(编码在指令里)可变(不同指令给不同的 )不变
谁是基准,谁是偏移PC 基准, 偏移BR 基准, 偏移 基准(数组首址),IX 偏移(下标)
面向转移、程序浮动面向系统:重定位、多道程序面向用户:数组、字符串、循环

一句话判据(能记这一句就够):

基址寻址里,寄存器是常量、形式地址是变量;变址寻址里,形式地址是常量、寄存器是变量。

展开看就明白为什么:

  • 基址:常量是”程序被装在主存哪里”(装入时定一次,运行中不变),变量是”要访问程序内部的哪个位置”(每条指令的 不同)。
  • 变址:常量是”数组在哪里”(首地址,编译时定),变量是”访问第几个元素”(循环里 IX 每轮 )。

注意变址寻址里 和 IX 的角色和基址寻址正好互换了——王道把数组首地址放在形式地址 里,把下标放在变址寄存器里。若记成”变址寄存器存数组首地址”就正好反了,后面所有推理都会跟着反。

基址与变址的复合

真实机器几乎总是把两者一起提供:x86 更进一步,还带一个比例因子:

那个 直接对应数组元素的字节数——int arr[] 用 ,double arr[] 用 ,所以 arr[i] 一步到位,不必先把 乘 4。这条硬件设计与 C 语言指针算术的对应关系,会在 4.3.1 的 LEA 那里再用一次。

堆栈寻址

栈顶,由 SP 隐含给出,指令里不出现地址。每次 PUSH/POP 自动修改 SP(多数机器的栈向低地址生长,PUSH 减 SP)。

两种实现,访存次数不同:

  • 硬堆栈:用一组专用寄存器做栈,不访存,但深度有限
  • 软堆栈:在主存里划一段,每次压弹都要访存一次,深度只受内存限制

“零地址指令不访存”这个说法只对硬堆栈成立,这是 4.1.2 已经提过的陷阱。

PC 相对寻址:基准是”已经加过的 PC”

这里的 是取指阶段自动增量之后的值,也就是下一条指令的地址,不是当前指令的地址。原因见 4.2.1:PC 的增量发生在取指周期,早于执行周期。

例 某机按字节编址,指令长 2 字节。地址 2000H 处有一条相对转移指令,位移量 。转移目标是多少? 取指后  ——不是 2006H。

位移量 是带符号补码,所以能向前也能向后跳。 位位移量的转移范围是这个范围有限,这正是”相对寻址只能做段内转移”的原因——跳出范围就必须换成直接寻址或间接寻址的长转移。

疑问点:偏移寻址三种的边界分别是什么,变址算是一种"思想"吗,随便找个寄存器就行吧

判据是”哪一半是变量”,上面那张表和那句判据就是完整答案。而”随便找个寄存器就行”这个判断——在真实 ISA 里完全正确,在 408 的分类语境里不成立,因为两边分的根本不是同一件事。

408 的分法真实 ISA 的分法
依据语义:谁维护这个寄存器、谁在变硬件:这个位置能不能填寄存器号
有没有专用寄存器概念上有 BR、IXx86 的 [base+index*s+disp] 里 base 和 index 几乎可填任意通用寄存器;MIPS 只有 offset(base) 一种,压根不分基址变址
结论基址 ≠ 变址同一套加法电路

所以”变址是一种思想”这个判断是对的——它确实是用途分类而非硬件分类。同一条 MOV AX,[BX+SI],把程序基址放 BX、下标放 SI 就是”基址+变址”;两个都放下标,硬件照算不误。硬件不知道也不关心谁是”基址”。

但考场上必须按 408 的语义分类答:问”哪种寻址方式便于程序重定位”答基址,问”哪种便于数组访问”答变址,问”两者硬件实现有何不同”答没有不同,都是寄存器内容加形式地址。

疑问点:基址寄存器是抽象层的,它的具体实现就是那些段寄存器和指针

“是抽象层”这半句对;“实现是段寄存器”这半句错——段寄存器不在同一层,它在下一层。

用 4.2.1 的地址翻译链定位一下就清楚了:

第 1 层  寻址方式        BX + SI + 8  ──►  EA(= 偏移地址 = 逻辑地址)
第 2 层  分段机制        DS × 16 + EA ──►  物理地址(8086 实模式)

拿 MOV AX, [BX+SI+8] 逐个归位:

8086 里的东西在哪一层对应 408 的什么
BX(Base)第 1 层基址寄存器 BR
SI(Source Index)第 1 层变址寄存器 IX
8第 1 层形式地址
DS(Data Segment)第 2 层不对应任何寻址方式

8086 里 408 的”基址寄存器”是有直接对应物的,就是 BX 和 BP——名字里的 B 就是 Base;SI/DI 里的 I 就是 Index。 段寄存器是另一回事:它属于地址空间的划分与保护,和寻址方式是正交的两层。

所以”8086 最后都归到了段地址 + 偏移地址”这句完全正确,但要补一句:那个”偏移地址”就是第 1 层算出来的 EA。它是寻址方式的输出、分段机制的输入,不是寻址方式的替代品。

换个角度:MIPS 根本没有段寄存器,但照样有基址寻址(lw $t0, 8($s0))。第 2 层可以整个不存在,第 1 层照常工作——这本身就证明了两者不是同一层的东西。

疑问点:相对寻址有利于程序浮动,这不是由基址寄存器决定的吗?我记得汇编时还有一个地址转换的过程

三句话都对,但它们说的是三种不同的机制,区别在于”什么时候生效”和”指令里的地址字段要不要被改写”。

机制谁做何时生效指令里的地址字段改吗解决什么范围的浮动
静态重定位链接器 / 装入程序装入时,一次性✅ 逐条改写(要重定位表)整个程序
基址寻址(动态重定位)OS 设 BR,硬件每次加每次访存❌ 只改 BR整个程序
PC 相对寻址硬件每次执行❌ 位移量本来就是相对的只管段内转移

记忆里”汇编后有一个地址转换的过程”指的是第一种——静态重定位。它确实存在,而且是三者里唯一真的去修改指令字节的。把它和后两种混成一件事,正是这个疑问的来源。

至于”相对寻址有利于浮动”和”基址寄存器有利于重定位”这两句,不冲突,因为管的范围不同:相对寻址管代码内部的相互引用(跳到本模块的某个标号),基址寻址管整个程序相对于主存的位置。一个程序两者都要用。

疑问点:写汇编时定义一个 L1 然后 jmp L1,L1 只是相对地址吧,那这里不是相对寻址?

前半句对,后半句反了——jmp L1 在 x86 上恰恰就是相对寻址,而且是最典型的一例。

关键在于:源码里的 L1 是一个符号,不是地址。 它最终变成什么,取决于汇编器为这条 jmp 选择了哪种机器指令编码:

你写的汇编器选的编码机器码里存的是用的寻址方式
jmp L1(同段,近)EB disp8 / E9 disp32位移量 下条指令地址PC 相对寻址
jmp far ptr L1EA ptr16:32段:偏移的绝对值直接寻址
jmp [table+bx]FF /4从主存取目标地址存储器间接寻址
jmp bxFF /4从寄存器取目标地址寄存器寻址

所以”是不是相对寻址”要看汇编器最终生成的机器指令,源码写法看不出来。 而 x86 的近转移默认就编码成相对形式,这就是为什么在实践里”jmp L1 是相对寻址”几乎总是成立的。

这也解释了那个”L1 只是相对地址”的直觉从哪来:汇编器算的确实是差值——disp = L1的地址 − 下一条指令的地址——而这个差值不随程序整体搬家而改变,所以整段代码平移之后,一个字节都不用动。这正是相对寻址”利于浮动”的全部含义。

8086 常用寄存器速查

统考不考 8086 的具体寄存器,但它是”哪个寄存器属于哪一层”最好的实例,也是上面几条辨析的落脚点。

分组寄存器全称用途在地址翻译链的哪一层
通用数据AXAccumulator累加器,算术运算、I/O——
BXBase可作基址第 1 层:基址寄存器
CXCount循环计数(LOOP)、串操作长度——
DXData乘除法高位、I/O 端口号——
指针SPStack Pointer栈顶指针堆栈寻址
BPBase Pointer栈帧基址,访问参数与局部变量第 1 层:基址寄存器
变址SISource Index源变址、串操作源第 1 层:变址寄存器
DIDestination Index目的变址、串操作目的第 1 层:变址寄存器
段CS/DS/SS/ESCode/Data/Stack/Extra Segment段基址第 2 层:分段机制
控制IPInstruction Pointer即 PC指令寻址
FLAGS标志寄存器,即 PSW条件转移

这张表的价值全在最后一列:BX/BP 与 SI/DI 在第 1 层,DS/SS 在第 2 层。名字里的 Base 和 Index 直接对应 408 的基址和变址,而段寄存器一个都不对应。

边界

“寻址方式”寻的是操作数的地址,不是操作数。 立即寻址是唯一的例外——它根本没有 EA, 字段里躺的就是操作数本身。所以严格讲”立即寻址的有效地址是多少”这个问题不成立,答案是”没有”。

相对寻址的基准是下一条指令的地址。 全章最高频的计算陷阱,例题算过一遍就不会再错。若题目特意说明”本机 PC 在执行阶段才更新”,则按题目口径来——题设永远优先于惯例。

间接寻址不等于寄存器间接寻址。 前者 要访存两次(一次取地址、一次取数),后者 只访存一次。“少一次访存”是寄存器间接寻址存在的全部理由。

基址寻址的 BR 可以是专用寄存器,也可以是某个通用寄存器。 若是通用寄存器,指令里就得给出它的编号,指令会长一点;若是专用寄存器,则隐含使用,指令短但不灵活。两种设计都有真实机器采用,题目会说明是哪种。

变址寻址与间接寻址可以复合,且顺序不同结果不同。

  • 前变址(先变址后间址):
  • 后变址(先间址后变址):

两者不等价,前者的变址结果是个地址的地址,后者的 先被解引用。题目给的括号位置就是判据,不要凭感觉。

堆栈寻址的”栈”向哪边长,题目必须给出。 多数机器向低地址生长(PUSH 时 ),但反向的机器存在。同时要注意 SP 指向的是”栈顶元素”还是”栈顶的下一个空位”,两种约定都有,影响 PUSH 是”先减后写”还是”先写后减”。

寻址方式的种类数受寻址特征字段位数限制。 位最多 种。若题目问”该机最多可支持几种寻址方式”,答 ;问”至少需要几位寻址特征”,答 种数。又是一组”最多”和”至少”,和 4.1.3 那组同理。

对照速查

寻址方式EA取操作数访存一句话记忆
隐含操作码隐含0~1省地址字段
立即无 EA0 就是数,补码
直接1范围
间接2范围大、可运行时改
寄存器0最快
寄存器间接1比间接省一次
相对1PC 是已增量的
基址1寄存器常、 变;面向系统
变址1 常、寄存器变;面向用户
堆栈栈顶0 硬 / 1 软SP 隐含
判断对错
立即寻址的有效地址等于 ❌(没有 EA)
立即数的范围是 ❌(补码,)
间接寻址访存 1 次❌(2 次)
相对寻址的基准是当前指令地址❌(下一条指令地址)
基址寻址中形式地址不变❌(可变,变的就是它)
变址寻址中变址寄存器存数组首地址❌(反了,首地址在 里)
基址与变址的硬件实现不同❌(同一套加法)
段寄存器是基址寄存器的具体实现❌(不在同一层)
jmp L1(近转移)不是相对寻址❌(正是相对寻址)
前变址与后变址等价❌

考点

  • 十种寻址方式的 EA 公式 + 访存次数,必须能默写
  • 总访存 = 取指 + 取操作数 + 存结果,间接寻址每多一级多一次
  • 立即寻址没有 EA,立即数是补码
  • 相对寻址的基准是已增量的 PC(下一条指令地址),位移量是补码,范围
  • 偏移寻址三兄弟公式相同:判据是「基址:寄存器常、 变;变址: 常、寄存器变」
  • 基址面向系统(重定位),变址面向用户(数组),硬件实现相同
  • 段寄存器属于分段机制(第 2 层),不是基址寄存器(第 1 层)的实现
  • 实现程序浮动有三种机制:静态重定位(改指令)、基址寻址(改 BR)、相对寻址(位移天然相对)
  • 前变址 与后变址 不等价
  • 寻址特征 位 → 最多 种寻址方式

链接