2

这个来源中,他们给出了 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 的编码指令。

4

2 回答 2

4

请参阅英特尔® 64 和 IA-32 架构软件开发人员手册第 2 卷:指令集参考,AZ,可在英特尔网站上以多种格式获取。翻到关于的页面CMP,找到带有 的行CMP r/m32, imm8。这将操作码列为83 /7 ib. 转至 表 2-2。带有 ModR/M 字节的 32 位寻址形式。选择[ebp]+disp8行和/digit 7列。单元格告诉您 ModR/M 字节是7d. 您需要附加8 位-4有符号的位移和您的直接操作数。fc完整的指令是这样的83 7d fc 02。如果在 64 位模式下使用rbp编码是一样的。如果你想保持ebp您需要使用地址大小覆盖前缀67.

于 2021-04-01T13:01:31.567 回答
3

除非您已经知道 x86 指令编码的工作原理,否则您链接的文档不是很有用。所以让我们尝试另一个。在此资源之后,我们得到以下候选编码:

81 /7 iw    CMP r/m16,imm16     Compare imm16 with r/m16.
81 /7 id    CMP r/m32,imm32     Compare imm32 with r/m32.
83 /7 ib    CMP r/m16,imm8      Compare imm8 with r/m16.
83 /7 ib    CMP r/m32,imm8      Compare imm8 with r/m32.

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

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

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

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

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

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

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

83  opcode
7d  modr/m byte: reg = 7, r/m = [ebp+disp8]
fc  displacement: -4
02  immediate: 2

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

于 2021-04-01T13:08:43.667 回答