一个指令能同时处于两种寻址模式吗?

5
我在书籍《从零开始编程》中读到了以下内容:
处理器有许多不同的访问数据的方式,称为寻址模式。最简单的模式是立即模式,其中要访问的数据嵌入在指令本身中。例如,如果我们想将一个寄存器初始化为0,我们不需要给计算机一个地址来读取0,而是指定立即模式,并将数字0传递给它。
寄存器寻址模式中,指令包含要访问的寄存器,而不是内存位置。其余的模式将涉及地址。
这是否意味着例如指令mov eax, 123既是立即模式又是寄存器寻址模式

1
逗号右边确定了寻址方式,因此是立即数寻址。与mov eax,ebx相比,那是寄存器寻址模式。 - Hans Passant
@Hans Passant,那么Peter Cordes的回答是错误的吗? - user8240761
2
@HansPassant:mov [eax+ecx],123怎么样?我认为谈论整个指令只有一个寻址模式是没有意义的。每个操作数都有自己的寻址模式。 - Peter Cordes
2个回答

8
并不是整个指令都有特定的寻址模式,而是每个操作数都有单独的寻址模式。在您的mov eax, 123示例中,可以说源操作数是立即数操作数,目的操作数是寄存器操作数。或者,如果要谈论整个指令的形式,可以说该指令的机器码将使用mov r, imm32编码的mov。 (还有一个mov r/m, imm32形式的mov,但是长度较长,因此良好的汇编程序只会在目标实际上是内存时才选择它。)但是,当其中一个操作数是寄存器时,为方便起见,您可以说“指令使用[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操作数,可以让您使用任意选择的正常寻址模式。因此,x86指令最多只有一个mod/rm字节。
有争议的是,立即操作数是否应该被称为“寻址模式”,因为数据不来自任何地方。它是指令的一部分。此外,指令的立即操作数形式具有与寄存器、寄存器/内存形式不同的操作码。
还要注意,大多数可以具有内存源或内存目的地的整数指令都有两个操作码:一个用于op r/m, r,另一个用于op r, r/m。(例如,请参见 and的参考手册条目,以及标签维基中的更多文档链接。)无论如何,and eax, ecx可以使用这两个操作码中的任何一个进行编码,由汇编器选择。对性能没有影响。

“Hans Passant”在我的问题评论中说:“逗号右侧决定寻址模式。所以这里是立即数寻址。与mov eax,ebx相比,那是寄存器寻址模式。”因此,我不知道你的答案是否正确还是他的答案正确! - user8240761
@user8240761:不要过于担心术语。不同的书籍/人使用不同的术语来描述相同的事物。但请注意,PGU中引用的文本并未说明整个指令具有寻址模式。(我已经浏览了PGU的部分内容,并推荐它。从我所看到的来看,作者似乎以一种明智的方式思考计算机和汇编语言。) - Peter Cordes

2
处理器有多种不同的访问数据的方式,称为寻址模式。
这句话是一般性描述处理器,并不特指某种类型的处理器。
我认为这种描述过于概括,因为总能找到例外情况。事实上,对于现代CPU而言,违反这一规则的CPU比遵循它的更多。
实际上,对于像6800或6502这样的“简单”CPU,指令本身只有一种寻址模式:
lda $3A

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

其他CPU确实在一条指令中有两种不同的寻址模式。例如,68000的“move”指令:

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] 操作数。) - Peter Cordes
我不确定你在说mov byte ptr的哪种形式,或者你在那段中想表达什么意思。大多数8086 ALU指令都有一个op [mem], immediate形式(使用一个op r/m, imm8...imm16操作码,其中mod/rm字节编码了内存寻址模式而不是寄存器)。 - Peter Cordes
@PeterCordes 我本想写 "隐式"(=无参数)。我纠正了一下。 - Martin Rosenau
@PeterCordes,m68k指令相当于mov word ptr [ecx+0x4567],word ptr [0x123],应该是mov m16,m16而非mov m16,imm16。我不知道amd64的情况,但i386没有这样的指令(除了movsw)。 - Martin Rosenau
啊对,m68k中的()圆括号是一种解引用,抱歉。我忘记了m68k有一种灵活的内存到内存移动方式,所以我只是以为那必须是立即数的语法 >.< 。x86的movsw实际上是隐含的movsw [es:edi], [esi],没有选择任何操作数的寻址方式(除了对esi进行段覆盖)。而且,AMD64并没有引入更多CISC指令。 - Peter Cordes
我仍然不清楚倒数第二段的意思。mov word ptr是什么意思? - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接