【问题标题】:Can an instruction be in two addressing modes at the same time?一条指令可以同时处于两种寻址模式吗?
【发布时间】:2017-12-05 07:37:05
【问题描述】:

我在从头开始编程一书中阅读了以下内容:

处理器有许多不同的方式来访问数据,称为 寻址模式。最简单的模式是立即模式,其中 要访问的数据嵌入在指令本身中。例如, 如果我们想将一个寄存器初始化为 0,而不是给 计算机读取 0 的地址,我们将指定立即 模式,并给它数字0。

寄存器寻址模式中,指令包含一个 注册访问,而不是内存位置。剩下的 模式将处理地址。

这是否意味着例如指令mov eax, 123 同时处于立即模式寄存器寻址模式

【问题讨论】:

  • 逗号右边的内容决定了寻址方式。这么快就到这里了。与 mov eax,ebx 相比,是寄存器寻址模式。
  • @Hans Passant 那么Peter Cordes的回答错了吗?
  • @HansPassant:mov [eax+ecx], 123 呢?我认为谈论具有一种寻址模式的整个指令是没有意义的。每个操作数都有自己的寻址模式。

标签: assembly x86 addressing-mode


【解决方案1】:

并不是整条指令都有特定的寻址模式,而是每个操作数分开。 在您的 mov eax, 123 示例中,您会说源是立即操作数,目标​​是寄存器操作数。

或者你可以说该指令的机器代码将使用mov r, imm32 encoding of mov,如果你想谈论整个指令所采用的形式。 (还有movmov r/m, imm32 形式,但它更长,所以一个好的汇编程序只会在目标实际上是内存时才选择它)。

但是,当其中一个操作数是寄存器时,为了方便和简洁,您可以根据需要说“该指令使用[base+index] 寻址模式”。但实际上,您正在谈论的是内存操作数,而不是整个指令。特别是如果您将寄存器和立即数算作“寻址模式”,即使不涉及内存地址。


此外,通常当人们说“寻址模式”时,他们指的是内存地址。从技术上讲,在 x86 中,大多数指令都有一个寄存器和一个寄存器/内存操作数,所以 add eax, ecxadd eax, [ecx] 之间的区别只是我认为 mod/rm 字节中的 1 位(在操作码之后)。

有些指令有两个内存操作数。例如,push qword [rdi + rax*8][rdi + rax*8] 显式加载并隐式存储到[rsp]。另一个例子是字符串指令movscmps,它们隐式使用[rdi][rsi]

但是没有指令有两个通用的 r/m 操作数,可以让您使用the normal addressing modes 的任意选择。所以一条 x86 指令最多有一个 mod/rm 字节。


立即操作数是否应该被称为“寻址模式”是有争议的,因为数据不是来自任何地方。这是指令的一部分。此外,指令的立即数形式与 reg、reg/mem 形式的操作码不同。

另请注意,大多数可以具有内存源或内存目标的整数指令都有两个操作码:一个用于op r/m, r,一个用于op r, r/m。 (例如,请参阅the ref manual entry for and,以及 标签 wiki 中的更多文档链接。)无论如何,and eax, ecx 可以使用两个操作码中的任何一个进行编码,这取决于汇编程序来选择。选择对性能没有影响。

【讨论】:

  • Hans Passant 在他对我的问题的评论中说:“逗号右边的内容决定了寻址模式。所以在这里很直接。比较 mov eax ,ebx, 那是寄存器寻址模式。”.所以我不知道你的答案是正确的还是他的答案是正确的!
  • @user8240761:不要太担心术语。不同的书/人使用不同的术语来描述同一件事。但请注意,您从 PGU 引用的文本中没有任何内容表明整个指令具有寻址模式。 (我略读了 PGU 的部分内容,并推荐它。从我所见,作者似乎以一种明智的方式思考计算机和 asm。)
【解决方案2】:

处理器有多种不同的数据访问方式,称为寻址模式。

这句话泛泛地谈论“处理器”,而不是特定的处理器类型。

我认为这太笼统了,因为您总是会发现这样的句子有例外。实际上,在查看现代 CPU 时,您会发现比遵循此规则的 CPU 更多的异常。

确实对于像 6800 或 6502 这样的“简单”CPU,指令本身具有一种寻址模式:

lda $3A

...例如使用“零页”或“直接”寻址模式。

其他 CPU 确实在一条指令中有两种不同的寻址模式。以68000的“移动”指令为例:

move.w ($123).w, (a3, $4567)

对于x86 CPU来说就更难说了:

在 6800 中,可以与 mov al, bl 比较的指令被命名为 tba(不带参数),而 mov al, [0x123] 被命名为 lda $123

所以你可以争辩 mov al, bl 是一条没有参数的指令(隐含寻址模式 - 因为该指令在其他 CPU 上写为 movblal 而没有任何操作数)并且 mov al, [0x123] 是具有一个内存地址参数的指令(绝对寻址模式 - 因为该指令在其他 CPU 上写为 ldal 0x123 和一个操作数)。

(原来的 8086 唯一不允许你这样争论的指令似乎是具有m8, imm8m16, imm16 寻址模式的指令,例如mov word ptr [123], 567add byte ptr [123], 45。)

当然,您可能还争辩说该指令是mov,而alblmov al, bl 指令的两个参数。

因此,如果指令 mov al, bl 是具有“隐含”(= 无操作数)或“寄存器到寄存器”寻址模式的指令,则取决于您的论点。

【讨论】:

  • 您的 m68k 示例等效于 x86 mov r/m16, imm16,即内存目标操作数和直接源操作数。如果您想要一个非常奇特的示例,VAX 指令可以为每个操作数具有任意寻址模式,例如两个操作数都可以是内存,可能带有后增量寻址或其他东西。 (在 x86 中,有些指令有两个内存操作数,但其中至少有一个是隐式的。没有一个采用两个 [base + idx*scale + displacement] 操作数。)
  • 我不确定which form of mov 你在谈论mov byte ptr,或者你在该段中的意思是什么。大多数 8086 ALU 指令都有op [mem], immediate 形式(使用op r/m, imm8...imm16 操作码和mod/rm 字节编码内存寻址模式而不是寄存器)。
  • @PeterCordes 我想写“隐含”(= 无参数)。我更正了。
  • @PeterCordes m68k 指令等价于mov word ptr [ecx+0x4567], word ptr [0x123],即mov m16, m16 而不是mov m16, imm16。我不知道amd64但i386没有这样的指令(movsw除外)。
  • 啊,对,m68k 中的() 括号是取消引用,抱歉。我忘记了 m68k 具有灵活的内存到内存移动,所以我只是假设它必须是立即 >.movsw is implicitly movsw [es:edi], [esi],没有为任一操作数选择寻址模式(esi 的段覆盖除外)。不,AMD64 没有引入更多的 CISC 指令。
猜你喜欢
  • 1970-01-01
  • 2014-09-10
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 1970-01-01
  • 2019-05-16
相关资源
最近更新 更多