2016-02-03 7 views
5

Das Programm mir Umkehr tut einfache Multiplikation zwischen Float-Zahl und 8 Byte integer:Wie dekompiliere ich diese x87-Assembly-Berechnung?

section .data 

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

section .text 
global main 

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

Ergebnis unter 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 

Ich versuche, dieses Programm in C (gleichen 32bit neu Umwelt):

#include <stdio.h> 

int main() { 

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

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

... aber ich habe sehr unterschiedliche Ergebnisse:

$ ./test 
6783712964982603776.000000 

Was ist falsch in meinem C-Programm ich tue?

+0

Was ist x87 Buddy? – m0skit0

+7

x87 ist eine Fließkomma-bezogene Teilmenge des x86-Architekturbefehlssatzes. => https://en.wikipedia.org/wiki/X87 – MCan

+6

@ m0skit0 Ein besser als ein x86, natürlich. – Neil

Antwort

8

Im asm-Code Sie Multiplikation tatsächlich zwei double s mit der fmul Anweisung, keine float und ein int. Tun etwas ähnliches 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; 
} 

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

LIVE DEMO

+0

Dies setzt voraus, dass 'long long int' und' double' die gleiche Breite haben. Kann das sicher gemacht werden? –

+0

OK - es dient nur zur Veranschaulichung, aber um alle glücklich zu halten, werde ich es in 'uint64_t' ändern. –

+1

Das habe ich gesucht, danke! – MCan

3

Dieser Assembler-Code zu tun ist nicht das, was Sie denken, es tut:

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

Sie vorschlagen einfache Multiplikation zwischen Float-Zahl und 8 Byte Integer. Dies ist tatsächlich eine Multiplikation eines erweiterten 10-Byte-Gleitkommawertes mit dem 8-Byte-Doppelwort (nicht 8-Byte-Ganzzahl), dargestellt durch 0x4141414142424242. 0x4141414142424242 wird als die Bits eines 8-Byte-Doppel-Gleitkommawerts von Ihrem Code behandelt, nicht eine 8-Byte-Ganzzahl, die in einen doppelten Gleitkommawert konvertiert wird.

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

Ihre Fehlinterpretation des Assembler-Code aufräumt Dies ist nur:

Der Code für das, was Sie glaubten, passierte etwas wie hätte aussah.