4

在我为 x86 平台上的 32 位 Linux 编写反汇编程序的冒险中,我遇到了一个问题。当我使用以下命令反汇编一个简单的 ELF-32 可执行文件时,我看到了以下操作码序列objdump

dc 82 04 08 0d 00     faddl  0xd0804(%edx)

但是当我查看英特尔手册时,我没有看到与此相对应的操作码。该fadd指令以 0xDC 开头,但随后需要一个m64fp操作数,即“内存中的内存四字操作数”。

现在,这是否意味着操作数是一个 64 位地址(这意味着该fadd指令是一个 64 位指令,但没有以 REX 字节为前缀),或者它只是一个指向的 32 位地址到四字(64 位)?

我是否在这里遗漏了一些琐碎的事情,或者我对编码 x86 指令的理解是错误的?

4

2 回答 2

5

让我们分解一下。

> dc 82 04 08 0d 00     faddl  0xd0804(%edx)
  |  |  \____ ____/
  |  |       V
  |  |       |
  |  |       +---------> 32-bit displacement
  |  +-----------------> ModRM byte
  +--------------------> Opcode

详细查看文档,dc确实以m64real浮点参数为源。它将这个 64 位参数添加到ST(0)浮点寄存器。

但是,决定 64 位值来自何处的是第二个字节。82这转换为以下的二进制 ModRM 字节:

+---+---+---+---+---+---+---+---+
| 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
+---+---+---+---+---+---+---+---+
|  MOD  |  REG/OPCD |    R/M    |

如果您查看链接文档中的表 2.2(用于 32 位寻址模式的表),您会发现它转换为disp32[EDX].

换句话说,它需要接下来的 32 位(四个字节),将其添加到edx寄存器并使用该地址从内存中提取 64 位值。

于 2011-11-15T06:01:03.990 回答
2

“内存中的四字操作数”表示该值在 RAM 中占用 64 位。地址大小取决于它是编译为 32 位还是 64 位进程,而不取决于操作数有多大。这是拆卸的完整细分。

  • 第一个字节,DC是操作码。结合下一个字节不在 C0 和 C7 之间,并且在寄存器字段(第 3-5 位)中包含 0 的事实,这表明fadd指令具有 64 位内存操作数。有趣的是l,操作码末尾的 表示一个 32 位操作数。应该是faddq

  • 第二个字节包含 3 个字段。

    • 位 6-7 表示最后一个字段的模式。
    • 位 3-5 是寄存器字段。由于该指令不需要寄存器操作数,因此它们被用作操作码的一部分。
    • 位 0-2 是 R/M 字段。它可以保存一个寄存器或指定一个内存操作数。组合模式10和 R/M010表示操作数是相对于edx寄存器具有 32 位地址的内存操作数。
  • 最后 4 个字节是操作数在 little endian 中的相对偏移量(最低有效字节在前)。

于 2011-11-15T05:59:28.560 回答