【问题标题】:What kind of address instruction does the x86 cpu have?x86 cpu有什么样的地址指令?
【发布时间】:2023-03-23 22:33:01
【问题描述】:

之前学过一地址、二地址、三地址指令,现在想知道,x86用的是什么地址指令?

【问题讨论】:

  • “地址”是指“操作数”吗?
  • @Sneftel:是的,在抽象的 ISA 分类术语中,它表示操作数。就像 MIPS 指令字中的 5 位寄存器字段一样是“地址”。 (我不知道geeksforgeeks.org/… 是否好用,但这是他们使用的术语)

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


【解决方案1】:

x86 是 CISC register machine,其中任何指令的最多 1 个操作数可以是 显式 内存地址而不是寄存器,使用像 [rdi + rax*4] 这样的寻址模式。 (有些指令可以有 2 个内存操作数,其中一个或两个是隐式的,不过:What x86 instructions take two (or more) memory operands?

典型的 x86 整数指令有 2 个操作数,都是显式的,例如 add eax, edx,它执行 eax+=edx

还有一些真正的 1 操作数 ALU 指令(没有隐含的其他操作数),例如 inc/decnegnot,它们是隐式 1 的加/减或从 0 的加/减的快捷方式,或与 -1 进行异或(一些具有不同的 FLAGS 语义)。还有bswap。此外,具有隐式 1 计数的移位/循环指令基本上是 1 操作数,并且某些汇编程序确实允许您编写 shr %eax

旧版 x87 FP 代码使用带有 x87 堆栈的 1 操作数指令,例如 faddp st1,其中 x87 堆栈的顶部 (st0) 是一个隐式操作数。还有一些像 fchs 这样的 0 操作数指令只对 st0 隐式运行。 (SSE2 是 x86-64 的基线,因此 x87 不再广泛使用。)

现代 FP 代码使用 SSE/SSE2 2 操作数指令,如 addsd xmm0,xmm1 或 3 操作数 AVX 编码,如 vaddsd xmm2, xmm0, xmm1

x86 指令有 0、1、2、3 甚至 4 个显式操作数。

有多种指令格式,但显式 reg/memory 操作数通常编码在操作码字节之后的 ModR/M 字节中。 (x86-64 instruction encoding on osdev 有很好的细节和图表)。它有 3 个字段:

  • r/m 操作数的 2 位模式(寄存器直接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/memory 目标或 reg/memory 源。如果您想要的操作数都是寄存器,您可以使用任一操作码,add r/m32, r32add r32, r/m32。 (一些汇编器have syntax to let you select the non-default encoding。理论上,汇编器/编译器可以使用这些选择作为水印来显示是哪个工具生成的。)

普通指令也有其他直接源形式的操作码,但通常它们使用 ModR/M 中的 reg 字段作为额外的操作码位,因此您仍然只能获得 2 个操作数,如 add eax, 123。一个例外是 imul 的直接形式加上 186,例如imul eax, [rdi + rbx*4], 12345。它不与其他立即指令共享编码空间,而是在 ModR/M 中具有寄存器 dst 和 r/m 源加上操作码隐含的立​​即操作数。

一些单操作数指令使用相同的技巧,即使用reg 字段作为额外的操作码位,但没有立即数。例如neg r/m32not r/m32inc r/m32shl/shr/rotate 编码移动隐式 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 ecxedx:eax = eax * ecx。一个显式源操作数、一个隐式源和 2 个隐式目标寄存器。 div/idiv 类似。

具有至少 1 个显式 reg/mem 操作数的指令对其使用 ModR/M 编码,但具有零显式操作数的指令(如 movsbcdq)没有 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], edxvaddps 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 来保存指令。

【讨论】:

  • two and three operand IMUL 实际上是用 186 引入的,而不是您写的 286。此外,您首先列出 ModR/M 字节的 reg 字段是“3 位 reg 字段,始终是寄存器号”,然后您最终添加它可以根据情况扩展操作码。我已经在列表条目中提到了这一点。
  • @ecm:关于 /r 的好建议,谢谢。是的,我上次告诉过你,我可能有几个答案,其中包括旧的 NASM 附录关于 imul 何时是新的错误信息。我看看能不能搜到其他案例。
  • @ecm: 2-operand 0F AF imul r, r/m 不是 386 中的新对象,不是 186 吗?你的ulukai.org/ecm/insref.htm 和当前的nasm.us/doc/nasmdocb.html 都这么说。 bitsavers.trailing-edge.com/components/intel/80186/… 只提到立即数 imul,而不是 2 操作数形式(奇怪的是作为单操作数立即数,不像另一个 186 手册)。当您说 2 操作数时,您是否计算了 imul eax, 123 形式,如果它与目标相同,汇编程序允许您省略提及第一个源?
  • 是的,我指的是三操作数指令的缩写形式,其目标和一个源相同的寄存器,最后一个操作数是立即数。但是,我应该更清楚一点;实际上,我确实错过了没有立即操作数的二操作数形式。你是对的,那个是 386+ 指令​​。
  • @ecm:好的,很好。如您所知,在机器代码中 imul-immediate 总是有 3 个操作数,它只是源代码级的简写。由于有一个 2 操作数形式是不同的指令,IMO 最好只讨论真实机器代码操作数的数量,无论您如何在源代码中编写它,至少在讨论存在哪些形式时什么时候介绍的。因为那是机器码问题。顺便说一句,我终于开始搜索和编辑我提到“imul”和“286”的答案。到目前为止大约有十几个。
猜你喜欢
  • 2011-06-28
  • 2023-03-14
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 2018-10-23
相关资源
最近更新 更多