我了解了一个地址,两个地址和三个地址指令,但是现在我想知道,x86使用哪种地址指令?
最佳答案
x86是CISC寄存器机,其中使用[rdi + rax*4]
之类的寻址模式,任何指令的最多1个操作数可以是显式内存地址而不是寄存器。 (尽管有些指令可以有两个内存操作数,但其中一个或两个都是隐式的,但是:What x86 instructions take two (or more) memory operands?)
典型的x86整数指令有2个操作数,它们都是显式的,例如 add eax, edx
,它执行eax+=edx
。
还有一些真正的1操作数的ALU指令(没有隐式其他操作数),例如inc
/ dec
,neg
和not
,它们是隐式1的加/减,或者0的sub的快捷方式,或者是-1的XOR(有些具有不同FLAGS语义) 。还有bswap
。同样,隐式计数为1的shift / rotate指令基本上是1操作数,某些汇编程序的确允许您编写shr %eax
。
传统x87 FP代码在x87堆栈中使用1操作数指令,例如faddp st1
,其中x87堆栈的顶部(st0
)是隐式操作数。 SSE2是x86-64的基线,因此不再被广泛使用。
现代FP代码使用SSE / SSE2 2操作数指令(例如addsd xmm0,xmm1
)或3操作数AVX编码(例如vaddsd xmm2, xmm0, xmm1
)
有x86指令,带有0、1、2、3甚至4个显式操作数。
指令格式有多种,但是显式的reg / memory操作数通常在操作码字节之后的ModR / M字节中进行编码。它具有3个字段:
reg
,注册间接[reg]
,[reg+disp8]
,[reg+disp32]
)。带位移位的模式表示这些字节跟随ModR / M字节。 r/m, immediate
指令中,used as extra opcode bits(例如,用于移位/旋转选择哪种类型。)大多数指令至少有2种编码可用,即reg /内存目标或reg /内存源。如果两个操作数都是寄存器,则可以使用
add r/m32, r32
或add r32, r/m32
之一的操作码。 (一些汇编器have syntax to let you select the non-default encoding。理论上,汇编器/编译器可以将这些选择用作水印,以显示产生该工具的工具。)通用指令还具有用于立即源格式的其他操作码,但是通常它们将ModR / M中的
reg
字段用作额外的操作码位,因此您仍然只能获得2个操作数,例如add eax, 123
。例外情况是立即添加186的imul
形式,例如 imul eax, [rdi + rbx*4], 12345
。它没有与其他立即指令共享编码空间,而是在ModR / M中具有寄存器dst和r / m源,以及操作码所隐含的立即操作数。一些单操作数指令使用相同的技巧将
reg
字段用作额外的操作码位,但没有立即数。例如neg r/m32
,not r/m32
,inc r/m32
或shl
/ shr
/旋转以隐式1移位(而不是cl
或立即数)的编码。因此,很遗憾,您不能复制和移动(直到BMI2)。有一些特殊情况的编码可以提高代码密度,例如
push rax
/ push rdx
的单字节编码将reg
字段打包到操作码字节的低3位中。在16/32位模式下,inc
/ dec
的任何字节的编码都为任何寄存器。但是在64位模式下,这些0x4?
代码用作REX前缀,以扩展reg
和r/m
字段以提供16个体系结构寄存器。还有一些指令包含一些或所有隐式操作数,例如
movsb
,它将一个字节从[rsi]
复制到[rdi]
,并且可以与rep
前缀一起使用以重复该rcx
时间。或者
mul ecx
执行edx:eax = eax * ecx
。一个显式源操作数,一个隐式源和2个隐式目标寄存器。 div
/ idiv
相似。具有至少1个显式reg / mem操作数的指令对其使用ModR / M编码,但是具有零显式操作数(如
movsb
或 cdq
)的指令没有ModR / M字节。他们只是有操作码。有些指令根本没有like mfence
,甚至没有隐含的操作数。立即操作数不能仅通过操作码本身通过ModR / M发出信号,因此
push imm32
or push imm8
具有自己的操作码。隐式目标(位于[rsp]
的内存,以及RSP本身已更新为rsp-=8
)。LEA是一种变通方法,它使x86 3操作数移位并添加,例如
lea eax, [rdi + rdi*2 + 123]
在一条指令中执行eax = rdi*3 + 123
。请参见Using LEA on values that aren't addresses / pointers?。目标寄存器在ModR / M的reg
字段中编码,而两个源寄存器在寻址模式下编码。 (涉及一个SIB字节,使用编码将由ModR / M字节用信号表示存在,否则将意味着base = RSP)。VEX前缀(由AVX引入)提供了3个操作数的指令,例如
bzhi eax, [rsi], edx
或vaddps ymm0, ymm1, [rsi]
。 (对于许多指令,第二个源是可选的内存,但对于某些指令,它是第一个源。)第三个操作数使用2或3字节VEX前缀编码。
有一些3操作数的非VEX指令,例如
vpblendvb xmm1, xmm2/m128, <XMM0>
之类的SSE4.1变量混合,其中XMM0是使用该寄存器的隐式操作数。AVX版本使其具有非破坏性(在VEX前缀中编码有单独的目标),并使混合控制操作数显式(以1字节立即数的高4位编码)。 这为我们提供了一个包含4个显式操作数
VPBLENDVB xmm1, xmm2, xmm3/m128, xmm4
的指令。 x86非常狂野,并且已经扩展了很多次,但是典型的整数代码主要使用2操作数指令,并附带大量LEA来保存指令。
关于x86 - x86 cpu有什么样的地址指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53325275/