Assembly 为什么不是';是否允许从内存移动到内存?

Assembly 为什么不是';是否允许从内存移动到内存?,assembly,x86,cpu-architecture,instruction-set,Assembly,X86,Cpu Architecture,Instruction Set,我想知道在装配时是否允许这样做 movl (%edx) (%eax) 我会猜到它访问第一个操作数中的内存并放入 第二个操作数的内存,类似于*a=*b,但我还没有看到任何处理此类的示例,所以我猜这是不允许的。 还有,有人告诉我这是不允许的 leal %esi (%edi) 为什么呢?最后,我应该知道还有其他类似的功能是不允许的 它是无效的。除了一组有限的操作数外,您不能在我熟悉的任何体系结构上直接执行内存到内存的移动。例如,通过英特尔兼容处理器上的SI和DI寄存器进行字符串move等操作

我想知道在装配时是否允许这样做

 movl (%edx) (%eax) 
我会猜到它访问第一个操作数中的内存并放入 第二个操作数的内存,类似于*a=*b,但我还没有看到任何处理此类的示例,所以我猜这是不允许的。 还有,有人告诉我这是不允许的

 leal %esi (%edi)

为什么呢?最后,我应该知道还有其他类似的功能是不允许的

它是无效的。除了一组有限的操作数外,您不能在我熟悉的任何体系结构上直接执行内存到内存的移动。例如,通过英特尔兼容处理器上的
SI
DI
寄存器进行字符串
move
等操作是例外,但应避免这些操作(见下文)。大多数体系结构都有助于这些有限的内存到内存的移动

如果你考虑一下硬件,这是非常有意义的。有地址线和数据线。处理器在地址线上发出要访问的内存地址的信号,然后通过数据线读取或写入数据。因此,数据必须通过缓存或处理器才能到达其他内存。事实上,如果你看一下第145页,你会看到一条强有力的声明,即永远不能使用
MOVS
及其朋友:

请注意,当REP MOVS指令向 目的地,它在同一时钟中从源读取下一个字 周期如果中的位2-4相同,则可能存在缓存组冲突 这两个地址位于P2和P3上。换句话说,你会得到一个 如果ESI+WORDSIZE-EDI为 可被32整除。避免缓存组冲突的最简单方法是 将源和目标对齐8。请勿在中使用MOVSB或MOVSW 优化的代码,即使在16位模式下也不行

在许多处理器上,REP MOV和REP STO可以通过移动快速执行 一次16字节或整个缓存线。只有当 满足某些条件。根据处理器的不同,条件也不同 对于快速字符串指令,通常情况下,计数必须为 高,源和目标必须对齐,方向必须 要向前,源和目标之间的距离必须在 源和源的缓存线大小和内存类型都最小 目标必须是写回或写合并(您可以 通常假设满足后一个条件)

在这些条件下,速度是您可以获得的最高速度 向量寄存器在某些处理器上移动甚至更快。而 字符串指令非常方便,必须强调这一点 在许多情况下,其他解决方案的速度更快。如果满足上述条件 如果不满足快速移动的要求,那么使用其他方法将获得很多好处 方法

从某种意义上说,这也解释了为什么寄存器到寄存器的移动是可以的(尽管还有其他原因)。也许我应该说,这解释了为什么他们不需要非常特殊的硬件在板上。。。寄存器都在处理器中;通过地址读写无需访问总线

movl (mem), (mem)

mov dword [eax], [ecx]    ; or the equivalent in Intel-syntax
无效,因为x86机器代码没有两个地址。(事实上,任何x86指令都不能有两种任意寻址模式。)

它有
mov r32,r/m32
mov r/m32,r32
。Reg Reg移动可以使用
mov r32,r/m32
操作码或
mov r/m32,r32
操作码进行编码。许多其他指令有两个操作码,一个是dest必须是寄存器,另一个是src必须是寄存器

(还有一些特殊形式,如
movr32、imm32
movabsr64、[64位绝对地址]

请参阅x86指令集参考手册(x86标记wiki中的链接)。我在这里使用Intel/NASM语法,因为insn ref手册就是这么做的

很少有指令可以加载和存储到两个不同的地址,例如
movs
(字符串移动)和
push/pop(mem)
()。在所有这些情况下,至少有一个内存地址是隐式的(由操作码暗示),而不是可以是
[eax]
[edi+esi*4+123]
或其他任意选择

许多ALU指令都有一个内存目标。这是对单个内存位置的读-修改-写操作,使用相同的寻址模式加载然后存储。这表明限制不是8086无法加载和存储,而是解码复杂性(以及机器码紧凑性/格式)限制


没有采用两个任意有效地址的指令(即使用灵活寻址模式指定)
MOV
具有隐式源操作数和目标操作数,
push
具有隐式目标操作数(esp)

x86指令最多有一个ModRM字节,ModRM只能对一个reg/内存操作数(模式为2位,基址寄存器为3位)和另一个仅寄存器操作数(3位)进行编码。使用转义码,ModRM可以向SIB字节发送信号,对内存操作数的基+标度索引进行编码,但仍然只有空间对一个内存操作数进行编码

如上所述,同一条指令(asm source助记符)的内存源和内存目标形式使用两种不同的操作码。就硬件而言,它们是不同的指令


选择这种设计的部分原因可能是实现的复杂性:如果一条指令可能需要来自AGU(地址生成单元)的两个结果,那么布线必须在那里才能实现。这种复杂性的一部分存在于解码器中,这些解码器可以确定操作码是哪条指令,并解析剩余的位/字节以确定操作码是什么
leal %esi, (%edi)
valid-asm.s:2: Error: number of operands mismatch for `lea'