5

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?

Blackwood
  • 4,504
  • 16
  • 32
  • 41
MCan
  • 59
  • 2

2 Answers2

8

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

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • This assumes `long long int` and `double` have the same width. Can that be safely made? – Fiddling Bits Feb 03 '16 at 16:46
  • OK - it's only for illustration purposes, but to keep everyone happy I'll change it to `uint64_t`. – Paul R Feb 03 '16 at 16:47
  • 1
    @MCan : If this answer solved you problem and was useful, please consider accepting it as an answer. You can find out more about the hows and whys of answering questions on SO here: http://meta.stackexchange.com/a/5235/271768 – Michael Petch Feb 15 '16 at 17:50
3

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.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198