大多数形式的 x86 寻址模式都没有真正的官方名称。它们都具有[base + index*scale + disp8/disp32] 的形式(或任何 1 或 2 个组件的子集),但 64 位 RIP 相对寻址除外。 Referencing the contents of a memory location. (x86 addressing modes).
英特尔确实在第 1 卷的第 3.7.5 节中正式命名了寻址模式的这些组件。它们还使用寄存器、立即数和内存,但通常不会对不同形式的寻址模式进行大肆宣传。
ModRM 字节中的 Mod 位是一个 2 位字段,这让我想知道是否可能有超过 4 种寻址模式。
Mod 使用 disp0/8/32 选择寄存器与内存。更多模式有“转义”代码
-
[rbp] 没有位移的模式意味着有一个没有基础的 disp32。 (这就是为什么你会在反汇编中看到[rbp+0]:[rbp] 的最佳编码是 base=rbp,disp8 为 0。(请注意,[rbp] 在它是帧指针时没有用。)
- 将是 base=rsp 的 ModR/M 编码意味着有一个 SIB 字节。
- 索引=RSP 的 SIB 编码意味着没有索引。 (鉴于前面的规则,这使得编码
[rsp] 成为可能,而不是不太有用的[rsp+rsp]。)
在用英语写汇编语言时,很自然地会使用含义明显的术语,包括您提到的一些术语。例如,Intel's optimization manual 说(我的重点):
2.3.2.4
微操作队列和循环流检测器 (LSD)
...(具有索引寻址模式的微融合微指令在 SnB 上的 IDQ 中未分层)
... 对于以 索引寻址 为主的代码(通常
发生在数组处理中),重新编码算法以使用基(或基+位移)寻址可以
有时通过融合加载加操作和存储指令来提高性能。
索引寻址模式包括使用idx*scale 的任何组合,无论它是使用基本reg 还是使用disp32,或两者兼而有之。 (idx 单独是不可编码的;[rax*1] 实际上被编码为 disp32+idx*1 和 disp32=0。)在某些时候他们说“任何带有索引的寻址模式”或类似的,否则可能不清楚它们到底是什么的意思。当然testing with performance counters可以验证解释。
但他们不会为事物编造名字。当没有明显的英语短语时,他们可以坚持某些东西,他们会写(仍在 Sandybridge 部分):
常见的加载延迟为五个周期。使用简单寻址时
模式,base plus offset小于2048,加载延迟可以是四个周期。
在表 2-19 中,它们有两列,一列用于 Base + Offset > 2048; 或
Base + Index [+ Offset],另一个用于Base + Offset < 2048,延迟低 1 个周期(256b AVX 负载除外)。 (有趣的是,[rdi+8] 的延迟比 [rdi-8] 低 1c。)
(从技术上讲,他们可能应该说“位移”,因为整个寻址模式在 x86 术语中形成一个偏移量或有效地址,当添加到段基址时形成一个线性地址。但“偏移量”也用于用非 x86 通用术语描述寻址模式的直接常数部分。幸运的是,现在您通常不必考虑 x86 分段。)
在第 1 卷手册中,英特尔确实使用了您描述的一些术语。他们将仅具有位移组件的寻址模式描述为“直接”(某种),[reg] 描述为“间接”,因为在谈论指令集及其支持的寻址模式时确实会使用这些术语。
vol.1 3.7.5 Specifying an Offset
以下寻址模式建议使用常见的组合
地址组件。
但正如您所看到的,它们不会为更复杂的形式编造名称。
不过,它们确实区分了即时操作数、寄存器操作数和内存操作数。 (3.7 操作数寻址)。不过,它们通常很少或根本没有区分使用寄存器编码的 r/m32 操作数与必须是寄存器的其他操作数。
分支指令术语
直接与间接也适用于分支机构。这有点像谈论寻址模式以达到接下来将要运行的代码字节。
6.3.7 64 位模式下的分支函数
...
地址大小会影响用于 JCXZ 和 LOOP 的 RCX 的大小;它们还会影响内存的地址计算
间接分支。这些地址默认为 64 位;但它们可以被地址大小覆盖为 32 位
前缀。
内存间接是jmp [rax],其中 RIP 的最终值来自内存,而不是像 jmp rax 这样设置 RIP=RAX 的寄存器间接分支。 x86 没有用于加载/存储的内存间接寻址模式;采用分支后的代码提取在术语中引入了额外的间接级别。 (有点)。
vol.2 manual entry for jmp 确实谈到了间接与相对或绝对跳跃。 (尽管请注意 x86 没有绝对直接 near 跳转(为此将地址放入寄存器中),只有使用立即指针(ptr16:16 或 ptr16:32)指定的绝对远地址或间接使用内存位置。)
在描述接近间接跳转时,jmp r/m32(或 64),他们说“在 GP reg 或内存中间接指定的绝对偏移量”。 (“绝对偏移量”是相对于 CS 段基数的)。
分段使 x86 寻址更难以讨论,尤其是在比较可以显式包含段的特殊寻址模式与不包含段的特殊寻址模式时。
命名寻址模式被高估了
记住 x86 寻址模式在一般情况的子集方面可以做什么要容易得多,而不是用 Indexed、Based 等名称分别记住所有不同的可能性。
您在诸如 https://www.tutorialspoint.com/microprocessor/microprocessor_8086_addressing_modes.htm 或 http://www.geeksforgeeks.org/addressing-modes/ 之类的教程中看到了对寻址模式进行分类的重要内容。后者甚至有一个测验,要求您将 C 语句与一些寻址模式名称进行匹配。
对于不太灵活的 16 位寻址模式,您可以尝试命名它们的数量很少,而基于与索引实际上确实为您提供了不同的寄存器选择。但是当你在编程时,你真正需要记住的是你可以选择[bx|bp] + [di|si] + disp0/8/16 的任何子集。这就是di/si(dst/src 索引)和bx/bp 的名称。
这样的术语在比较不同 ISA 的功能时很有用。例如,Wikipedia says 说像 PDP-8 这样的旧 ISA 大量使用内存间接,因为它们的寄存器很少,而且寄存器的寻址范围只有 8 位。
维基百科还说:
请注意,没有公认的命名各种寻址模式的方式。
对模式的命名没有意义。如果您正在写东西,请确保清楚您的意思,而不依赖于某些术语的特定技术含义。例如如果您说“索引寻址模式”,请确保读者从上下文中知道您是否包含base+index*scale。
我想知道命名模式的某些愿望是否源于早于 8086 的 8 位微控制器。您可能想在https://retrocomputing.stackexchange.com/ 上询问这个问题。我不太了解 8 位 CPU 上可用的寻址模式,这些寻址模式大多是固定的一字节指令。