2011-11-15 42 views
4

在我为Linux x86-32位平台编译反汇编程序的冒险中,遇到了一个问题。我看到下面的操作码序列,当我拆开使用“objdump的”一个简单的ELF-32可执行:拆解'faddl'指令

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

但是,当我看英特尔手册[1],我没有看到一个操作码correspoding了这一点。 'fadd'指令以0xdc开始,但它需要'm64fp'操作数,即“内存中的内存四字操作数”。现在,这是否意味着操作数是一个64位地址(这意味着fadd指令是一个64位指令,但没有以rex字节为前缀),还是只是指向一个32位地址四字(64位)?

我在这里错过了一些微不足道的东西,还是我对编码x86指令的理解错误?

[1] http://www.intel.com/design/intarch/manuals/243191.HTM

感谢和问候,
Hrishikesh穆拉利

+0

对不起,但我还没有看过很长一段时间。现在就做。 –

+0

请注意,英特尔手册使用英特尔标记,而Linux使用AT&T标记,因此您将无法直接在英特尔手册中查找Linux操作码。 –

回答

2

“四字操作数在存储器中” 是指值取为64位在RAM中。地址大小取决于它是否被编译为32或64位进程,而不是操作数的大小。这里是反汇编的完整分解。

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

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

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

+0

谢谢,我会先详细阅读文档。我想我正在尝试跳跃,但效果并不好。 –

+0

也许'faddl'适用于他32位位移操作数而不是它指向的64位四字? – paxdiablo

+0

@paxdiablo不,指令后缀总是指操作数大小。你可以通过它适合的范围来确定位移的大小(0xd0804适合32位,但不能是8位),但它没有明确说明,因为它通常并不重要。 – ughoavgfhw

5

让我们来分解一下。

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

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

但是,它是字节82正在决定64位值来自哪里。这转化为二进制字节ModRM:

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

如果您链接的文档(一个为32位寻址模式),在看表2.2,你会看到这个转化为disp32[EDX]

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

+1

谢谢!我想我应该先详细研究文档。 –