【问题标题】:How to encode an instruction when we just know the hex for opcode当我们只知道操作码的十六进制时如何编码指令
【发布时间】:2021-04-01 12:49:25
【问题描述】:

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

【问题讨论】:

  • 请注意,cmp r/m, imm8 的“十六进制”(相应的“操作码”)不是0x837。这是0x83 /7。这是完全不同的事情。

标签: assembly x86 x86-64 instruction-encoding


【解决方案1】:

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

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 位模式下运行)以及是否存在 66REX.W 操作数大小覆盖确定字首。规则很简单:

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

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

现在的问题是使用83 还是81。在这种情况下,两者都可以使用,因为我们的立即数适合 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

【讨论】:

  • 感谢您的回答。特别是,我不明白第二个字节。如果指令有 [esp-4] 而不是 [ebp-4],那么我想更改只发生在第二个字节中。但我无法弄清楚发生了什么变化。
  • esp 是一种特殊情况,因为它也需要一个 SIB 字节。所以你选择[--][--]+disp8行,它给你7c的modr/m然后SIB表行缩放索引none和列基esp给你24所以完整的指令然后是83 7c 24 fc 02跨度>
  • 一个小疑问,如何在nasm中声明一个有读权限的section?如果我写section .custom exec write read,它会给出main.asm:139: warning: Unknown section attribute 'read' ignored on declaration of section '.custom' 错误!
  • 因为没有read属性。请咨询manual
  • 是的,谢谢。它在没有读取属性的情况下正确执行。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2020-11-29
    • 2012-04-06
    • 1970-01-01
    • 2014-05-18
    • 2011-12-09
    • 1970-01-01
    • 2019-11-22
    • 1970-01-01
    • 2016-04-17
    相关资源
    最近更新 更多