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 的编码指令。
除非您已经知道 x86 指令编码的工作原理,否则您链接的文档不是很有用。那么让我们尝试另一种。根据此资源(从英特尔官方 PDF 手册1中抓取),我们得到以下候选编码:
\n81 /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.\nRun Code Online (Sandbox Code Playgroud)\n这里需要注意的一件事是,对于字和双字操作都给出了相同的编码。这不是一个错误:操作数大小由当前代码段的默认操作数宽度(即我们是否在 16 位、32 位模式或 64 位模式下运行)以及操作数大小覆盖前缀的存在66确定REX.W。规则很简单:
66在 16 位和 32 位操作数大小之间切换REX.W前缀切换为 64 位操作数大小因此,在 32 位或 64 位模式下编程时,不需要前缀,因为默认操作数大小已经是我们想要的大小。
\n现在的问题是是否使用83or 81。在这种情况下,两者都可以使用,因为我们的立即数适合 8 位带符号的。83由于编码较短,我们将继续使用操作码。
编码83 /7 ib告诉我们操作码是83后跟一个 reg = 7 的 modr/m 字节(其他字段对 r/m32 操作数进行编码),后跟一个 8 位立即数。
r/m32 操作数[ebp-4]可以在您链接的参考文献中给出的 modr/m 字节表中查找。我们有一个具有索引寻址模式的内存操作数;指数ebp和位移-4。位移适合有符号的 8 位,因此我们使用表中的条目并以 modr/m 字节[ebp+disp8]结束。7d接下来是位移字节,0xfc为二进制补码的 \xe2\x88\x924。
把它们放在一起,我们得到的83 7d fc 02编码是cmp dword ptr [ebp-4], 2:
83 opcode\n7d modr/m byte: reg = 7, r/m = [ebp+disp8]\nfc displacement: -4\n02 immediate: 2\nRun Code Online (Sandbox Code Playgroud)\n值得注意的是,32 位和 64 位模式的编码是相同的。对于 16 位模式,需要额外的66和前缀来选择 32 位操作数和地址大小,给出.6766 67 83 7d fc 02
脚注1:在Intel的软件开发手册(SDM)中,指令的操作数大小属性在第1卷第1章中有描述。3.6、以及66h选择非默认模式的前缀在第 2 卷第 1 章中有描述。2.1.1 第 3 组。
其他编码细节大部分在vol.2手册中。像https://www.felixcloutier.com/x86/和https://c9x.me/x86/这样的网站是从 Intel 的 vol.2 PDF 中抓取的,但仅包含每条指令的条目,而不包含介绍内容它告诉您适用于每条指令的基础知识,或如何阅读条目的详细信息。另请参阅如何读取英特尔操作码表示法
\n