【问题标题】:How to decompile this x87 assembly calculation?如何反编译这个 x87 汇编计算?
【发布时间】:2016-05-12 23:20:04
【问题描述】:

我正在反转的程序在浮点数和 8 字节整数之间进行简单的乘法:

section .data

va: dt 1.4426950408889634074
vb: dd 0x42424242
    dd 0x41414141

section .text
global main

main:
    fld tword[va]
    fmul qword[vb]
    ret

gdb 下的结果:

Breakpoint 1, 0x08048360 in main ()
(gdb) x/i $eip
0x8048360 <main>:       fld    TBYTE PTR ds:0x804953c
0x8048366 <main+6>:     fmul   QWORD PTR ds:0x8049546
0x804836c <main+12>:    ret
(gdb) x/gx 0x8049546
0x8049546 <vb>: 0x4141414142424242
(gdb) si
0x08048366 in main ()
0x0804836c in main ()
(gdb) info float
=>R7: Valid   0x4014c726039c95268dc4 +3262848.902912714389

我正在尝试在 C 中重新创建这个程序(相同的 32 位环境):

#include <stdio.h>

int main() {

    unsigned long long vb = 0x4141414142424242LL;
    float r, va = 1.4426950408889634074F;

    r = va * vb;
    printf("%f\n", r);
}

...但我得到了非常不同的结果:

$ ./test
6783712964982603776.000000

我在我的 C 程序中做错了什么?

【问题讨论】:

  • x87 是 x86 架构指令集的浮点相关子集。 => en.wikipedia.org/wiki/X87
  • @m0skit0 当然比 x86 好。
  • 0x4141414142424242 x 1.4426950408889634074 绝对是 6783712964982603776.000000,而不是 3262848.902912714389。
  • @m0skit0:如果你的个人资料图片暗示你那么老,你应该知道;-)
  • @Olaf 事实上我知道,因为我什至有一个 387,我只是被这个符号弄糊涂了:^P

标签: c assembly floating-point reverse-engineering x87


【解决方案1】:

在 asm 代码中,您实际上是将两个 doubles 与 fmul 指令相乘,而不是 floatint。在 C 中做类似的事情:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main()
{
    uint64_t vbi = 0x4141414142424242ULL; // hex representation of double
    double r, vb, va = 1.4426950408889634074;

    memcpy(&vb, &vbi, sizeof(vb));        // copy hex to double
    r = va * vb;
    printf("va = %f, vb = %f, r = %f\n", va, vb, r);
    return 0;
}

结果 = va = 1.442695, vb = 2261634.517647, r = 3262848.902913.

LIVE DEMO

【讨论】:

  • 这假定long long intdouble 具有相同的宽度。可以安全地制造吗?
  • 好的 - 仅用于说明目的,但为了让大家开心,我将其更改为 uint64_t
  • @MCan :如果此答案解决了您的问题并且有用,请考虑接受它作为答案。你可以在这里找到更多关于如何和为什么回答问题的信息:meta.stackexchange.com/a/5235/271768
【解决方案2】:

这个汇编代码没有做你认为它正在做的事情:

main:
    fld tword[va]
    fmul qword[vb]
    ret

您建议 浮点数和 8 字节整数之间的简单乘法。这实际上是 10 字节扩展双精度浮点值乘以 0x4141414142424242 表示的 8 字节双精度(不是 8 字节整数)。 0x4141414142424242 被您的代码视为 8 字节双精度浮点值的位,而不是转换为双精度浮点值的 8 字节整数。

您认为正在发生的事情的代码可能类似于:

main:
    fild qword[vb]     ; Convert 64-bit integer to an extended precision double in st0
    fld tword[va]      ; st(0)=>st(1) st(0) = 10-byte float(va)
    fmulp              ; Multiply st(0) and st(1). Result in st(0).

这只是消除了您对汇编代码的误解。

【讨论】:

    猜你喜欢
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 2015-12-21
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    相关资源
    最近更新 更多