Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decompile this x87 assembly calculation?

The program I'm reversing does simple multiplication between float number and 8 byte integer:

section .data

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

section .text
global main

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

Result under 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

I'm trying to recreate this program in C (same 32bit environment):

#include <stdio.h>

int main() {

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

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

...but I get very different results:

$ ./test
6783712964982603776.000000

What I'm doing wrong in my C program?

like image 867
MCan Avatar asked Feb 03 '16 16:02

MCan


2 Answers

In the asm code you're actually multiplying two doubles with the fmul instruction, not a float and an int. To do something similar in 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;
}

Result = va = 1.442695, vb = 2261634.517647, r = 3262848.902913.

LIVE DEMO

like image 60
Paul R Avatar answered Oct 15 '22 02:10

Paul R


This assembler code is not doing what you think it is doing:

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

You suggest simple multiplication between float number and 8 byte integer . This is actually multiplication of a 10-byte extended double floating point value by the 8-byte double (not 8-byte integer) represented by 0x4141414142424242 . 0x4141414142424242 is treated as the bits of an 8-byte double floating point value by your code, not an 8-byte integer converted to a double floating point value.

The code for what you believed was happening could have looked something like:

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).

This just clears up your misinterpretation of the assembler code.

like image 28
Michael Petch Avatar answered Oct 15 '22 03:10

Michael Petch