在我为x86平台上的32位Linux编写反汇编程序的尝试中,我遇到了一个问题。当我使用objdump
反汇编一个简单的ELF-32可执行文件时,我看到了以下操作码序列:
dc 82 04 08 0d 00 faddl 0xd0804(%edx)
但是当我查看Intel manual时,我没有看到与此对应的操作码。 fadd
指令以0xDC开头,但是它需要一个m64fp
操作数,即“内存中的内存四字操作数”。
现在,这是否意味着操作数是64位地址(这意味着fadd
指令是64位指令,但不以REX字节为前缀),或者是只是一个32位地址,指向一个四字(64位)?
我在这里遗漏了一些微不足道的东西,还是我对编码x86指令的理解错了?
答案 0 :(得分:5)
让我们打破这一点。
> dc 82 04 08 0d 00 faddl 0xd0804(%edx)
| | \____ ____/
| | V
| | |
| | +---------> 32-bit displacement
| +-----------------> ModRM byte
+--------------------> Opcode
详细查看文档,dc
确实是以m64real
浮点参数作为源。它会将此64位参数添加到ST(0)
浮点寄存器。
但是,第二个字节82
决定了64位值的来源。这转换为:
+---+---+---+---+---+---+---+---+
| 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
+---+---+---+---+---+---+---+---+
| MOD | REG/OPCD | R/M |
如果查看链接文档中的表2.2(32位寻址模式的表),您会看到这会转换为disp32[EDX]
。
换句话说,它需要接下来的32位(四个字节),将其添加到edx
寄存器并使用该地址从内存中提取64位值。
答案 1 :(得分:2)
“内存中的四字操作数”表示该值在RAM中占用64位。地址大小取决于它是编译为32位还是64位进程,而不是编译器操作数的大小。以下是拆卸的完整细分。
第一个字节DC
是操作码。结合下一个字节不在C0和C7之间,并且在寄存器字段(第3-5位)中包含0的事实,这表示具有64位存储器操作数的fadd
指令。有趣的是,操作码末尾的l
表示32位操作数。它应该是faddq
。
第二个字节包含3个字段。
10
和R / M 010
表示操作数是一个内存操作数,相对于edx
寄存器具有32位地址。最后4个字节是小端(最低有效字节优先)中操作数的相对偏移量。