x86 - x86 cpu有什么样的地址指令?

标签 x86 cpu computer-science cpu-architecture instruction-set

我了解了一个地址,两个地址和三个地址指令,但是现在我想知道,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 / decnegnot,它们是隐式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个字段:

  • 2位模式,用于r / m操作数(注册直接reg,注册间接[reg][reg+disp8][reg+disp32])。带位移位的模式表示这些字节跟随ModR / M字节。
  • 3位r / m字段(用于寄存器直接或间接的寄存器号,或者可以是转义码,这意味着ModRM后有一个Scale / Index / Base SIB字节,可以为r / m编码缩放索引寻址模式操作数)。有关特殊情况/转义代码的详细信息,请参见rbp not allowed as SIB base?
  • 3位reg字段,始终是一个寄存器号。 (或者在单操作数或r/m, immediate指令中,used as extra opcode bits(例如,用于移位/旋转选择哪种类型。)

  • 大多数指令至少有2种编码可用,即reg /内存目标或reg /内存源。如果两个操作数都是寄存器,则可以使用add r/m32, r32add 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/m32not r/m32inc r/m32shl / shr /旋转以隐式1移位(而不是cl或立即数)的编码。因此,很遗憾,您不能复制和移动(直到BMI2)。

    有一些特殊情况的编码可以提高代码密度,例如push rax / push rdx的单字节编码将reg字段打包到操作码字节的低3位中。在16/32位模式下,inc / dec的任何字节的编码都为任何寄存器。但是在64位模式下,这些0x4?代码用作REX前缀,以扩展regr/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/

    相关文章:

    assembly - 获取非法指令异常的最简单方法

    assembly - 是否可以使用向量指令对数组中每 3 个相邻元素求和并使它们中的每一个都等于总和?

    x86 - 现代 x86 CPU 使用什么缓存一致性解决方案?

    architecture - (Nand2tetris CPU)每个时钟周期发生(什么/多少)?

    c - 测量 CPU 频率 (x86/x64)

    cpu - 如何减少 Circle CI 或 Travis CI 上的 Elm 编译时间?

    elasticsearch - Elastic Search Scroll API对CPU的影响

    java - 多次构造同一对象的良好风格

    functional-programming - Jan Willem Klop 的 "(L L L...)"Y 组合器如何工作?

    algorithm - 给定一个未排序的数组 A,检查 A[i] = i 是否有效存在