当我们只知道操作码的十六进制时如何对指令进行编码

Sou*_*a B 3 x86 assembly x86-64 instruction-encoding

来源中,他们给出了 cmp r/m16/32 imm8 的十六进制为 0x837。我在哪里得到的,ebp 的十六进制是 0b0101。有了这些信息,我如何对指令进行编码cmp dword [ebp-4] 2?我已经搜索了几个小时,除了这个(第 61 页)cmpb $0xf,(%rdi)编码为 80 3f 0f 的类似指令之外,没有任何线索。但我无法理解这一点,因为我提到的前一个来源说 0x803 是针对 sbb 的。另外,rdi 是 0b0111 而不是 0b1111(实际上是 r15)。我很困惑...如果可能的话,我想要 x86-32 和 x86-64 的编码指令。

fuz*_*fuz 6

除非您已经知道 x86 指令编码的工作原理,否则您链接的文档不是很有用。那么让我们尝试另一种。根据此资源(从英特尔官方 PDF 手册1中抓取),我们得到以下候选编码:

\n
81 /7 iw    CMP r/m16,imm16     Compare imm16 with r/m16.\n81 /7 id    CMP r/m32,imm32     Compare imm32 with r/m32.\n83 /7 ib    CMP r/m16,imm8      Compare imm8 with r/m16.\n83 /7 ib    CMP r/m32,imm8      Compare imm8 with r/m32.\n
Run Code Online (Sandbox Code Playgroud)\n

这里需要注意的一件事是,对于字和双字操作都给出了相同的编码。这不是一个错误:操作数大小由当前代码段的默认操作数宽度(即我们是否在 16 位、32 位模式或 64 位模式下运行)以及操作数大小覆盖前缀的存在66确定REX.W。规则很简单:

\n
    \n
  • 在16位模式下,默认操作数大小为16位
  • \n
  • 在32位和64位模式下,默认操作数大小为32位
  • \n
  • 前缀66在 16 位和 32 位操作数大小之间切换
  • \n
  • 在 64 位模式下,REX.W前缀切换为 64 位操作数大小
  • \n
\n

因此,在 32 位或 64 位模式下编程时,不需要前缀,因为默认操作数大小已经是我们想要的大小。

\n

现在的问题是是否使用83or 81。在这种情况下,两者都可以使用,因为我们的立即数适合 8 位带符号的。83由于编码较短,我们将继续使用操作码。

\n

编码83 /7 ib告诉我们操作码是83后跟一个 reg = 7 的 modr/m 字节(其他字段对 r/m32 操作数进行编码),后跟一个 8 位立即数。

\n

r/m32 操作数[ebp-4]可以在您链接的参考文献中给出的 modr/m 字节表中查找。我们有一个具有索引寻址模式的内存操作数;指数ebp和位移-4。位移适合有符号的 8 位,因此我们使用表中的条目并以 modr/m 字节[ebp+disp8]结束。7d接下来是位移字节,0xfc为二进制补码的 \xe2\x88\x924。

\n

把它们放在一起,我们得到的83 7d fc 02编码是cmp dword ptr [ebp-4], 2

\n
83  opcode\n7d  modr/m byte: reg = 7, r/m = [ebp+disp8]\nfc  displacement: -4\n02  immediate: 2\n
Run Code Online (Sandbox Code Playgroud)\n

值得注意的是,32 位和 64 位模式的编码是相同的。对于 16 位模式,需要额外的66和前缀来选择 32 位操作数和地址大小,给出.6766 67 83 7d fc 02

\n
\n

脚注1:在Intel的软件开发手册(SDM)中,指令的操作数大小属性在第1卷第1章中有描述。3.6、以及66h选择非默认模式的前缀在第 2 卷第 1 章中有描述。2.1.1 第 3 组。

\n

其他编码细节大部分在vol.2手册中。像https://www.felixcloutier.com/x86/https://c9x.me/x86/这样的网站是从 Intel 的 vol.2 PDF 中抓取的,但仅包含每条指令的条目,而不包含介绍内容它告诉您适用于每条指令的基础知识,或如何阅读条目的详细信息。另请参阅如何读取英特尔操作码表示法

\n

  • `esp` 是一种特殊情况,因为它也需要 SIB 字节。因此,您选择“[--][--]+disp8”行,它为您提供“7c”的 modr/m,然后 SIB 表行缩放索引“none”和列基“esp”为您提供“24”,因此完整的指令是 `83 7c 24 fc 02` (2认同)