Gleitkommazahlen P4 Gnu ASM



  • Hallo Forum,

    ich versuche mich zum ersten Mal an Gleitkommazahlen. Leider mit wenig Erfolg. Laut Intel instruction set will FLD unter anderem als Parameter:
    FLD m32fp

    Also hab ich einiges durchprobiert:
    fld $4

    oder
    bla: .float 3
    fld $bla

    oder:
    mov $3, %eax
    fld %eax

    Das Einzige was funktioniert hatte war über den Stack.
    push $3
    fld (%esp)

    Was genau meint das m32fp?

    Danke für jede nützliche Antwort 🙂

    PS: Noch ne kleine Frage hinten dran.
    Kann man in der instruction set Doku irgendwo ablesen wie viele Takte ein Befehl braucht?



  • r2p2 schrieb:

    Was genau meint das m32fp?

    Ich wuerde mal behaupten, das meint ein 32Bit float im Speicher.
    Dann noch einige Kommentare zu deinen Versuchen:

    r2p2 schrieb:

    Also hab ich einiges durchprobiert:
    fld $4 - ist weder Float noch Speicherzugriff

    oder
    bla: .float 3
    fld $bla - dito

    oder:
    mov $3, %eax
    fld %eax - Zugriff via Register ist auch nicht moeglich

    Das Einzige was funktioniert hatte war über den Stack.
    push $3
    fld (%esp) - klar, ist zwar auch kein float, aber immerhin ein Speicherzugriff

    r2p2 schrieb:

    PS: Noch ne kleine Frage hinten dran.
    Kann man in der instruction set Doku irgendwo ablesen wie viele Takte ein Befehl braucht?

    Ich kenne diese Intel Doku nicht. Wenn es nicht offensichtlich ist, schau doch auch mal in anderen Referenzen nach (siehe zB. auch FAQ).



  • Ok. Ich seh ein das der was aus dem Speicher haben will.
    Das mit dem Stack finde ich aber sehr unpraktisch.

    In einem Buch das vor mir liegt schieben die ein
    A DD 3.5
    aus dem Datensegment über
    FLD A
    in das Register.

    Klappt nur bei meinem gnu asm net 😕
    äußerst merkwürdig...



  • r2pr2 schrieb:

    Ok. Ich seh ein das der was aus dem Speicher haben will.
    Das mit dem Stack finde ich aber sehr unpraktisch.

    ...? Muss doch nicht ueber den Stack laufen.

    r2pr2 schrieb:

    In einem Buch das vor mir liegt schieben die ein
    A DD 3.5
    aus dem Datensegment über
    FLD A
    in das Register.

    Da wird halt einfach ein 32Bit float im Speicher beim Label "A" abgelegt und dann geladen. Wie das in AT&T-Syntax, spezieller beim GAS aussehen muss, kann ich dir aber leider auch nicht sagen.



  • Hallo,

    so sollte es gehen:

    a: .float 1.0
    b: .double 1.0
    
    flds a
    fldl b
    

    Variable a ist ein float, 4 Bytes, geladen wird mit der Instruktion flds (s steht für single (= float)). Variable b ist ein double, 8 Bytes, geladen wird mit der Instruktion fldl (l steht für long...).
    Wenn du so was machst:

    movl $a, %eax
    

    dann wird die Adresse von a nach eax geladen.
    Schreibst du dagegen so was:

    movl a, %eax
    

    Dann wird das, was an der Adresse a steht (in unserem Fall ein float, 1.0, in hex 3FF00000h o.ä.), nach eax geladen.
    Das ist auf den ersten Blick ungewohnt und manch einer bekommt davon "Augenkrebs" (hatte das irgendwo hier im Forum gelesen), ist aber nach einiger Zeit, wenn man sich daran gewöhnt hat, sehr logisch.
    Wenn man das oben berücksichtigt, müsste es auch noch so funktionieren:

    movl $a, %eax
    flds (%eax)
    

    Die Adresse von a nach eax, danach direkt Adresse in eax benutzen, um auf die Variable zuzugreifen...
    Hoffe, es hilft weiter.



  • Kurze Anmerkung noch:

    Das Einzige was funktioniert hatte war über den Stack.
    push $3
    fld (%esp)

    Behaupte, das hat nicht funktioniert. Eine dezimale 3 ist zwar auf dem Stack, das ist aber keine Fliesskommazahl 3.0. Im schlimmsten Fall hast du die NaN geladen...
    So müsste es wie gedacht funktionieren:

    a: .float 3.0
    
    movl a, %eax
    pushl %eax
    flds (%esp)
    

    Erst den Inhalt der Variable a nach eax laden, dann den Inhalt von eax auf den Stack pushen und erst danach mit fld vom Stack holen...



  • .text
    .globl main
    main:
    	flds a
    	fadds b
    	fsts a
    	mov a, %eax
    	push %eax
    	push $text
    	call printf
    	push $0
    	call exit
    
    .data
    text:	.string "zahl: %f\n\0"
    a: .float 1
    b: .float 2
    

    Ich danke dir vielmals. Im eax Register stehts schon richtig drin. Das mir printf immer -0,00000 ausgibt ist erstmal nicht so wichtig.
    Bisher war ich der Meinung das $ greift auf den Wert und nicht auf die Adresse zu. Erstaunlich das ich mit dieser Einbildung so weit so Fehlerfrei gekommen bin.
    Ist für mich nur sehr ungewohnt, weil ja int $0x80 auch den Wert meint und nicht die Adresse dahinter.
    Sehr bedauerlich das die GNU ASM Dokus und Tutorials alle viel zu kurz sind.

    Danke nochmal 🙂



  • Viel schlimmer ist jedoch:
    Ich finde keine Intel-instruction die mir das Vergleichen zweiter
    floating point numbers ermöglicht.
    Muss ich nochmal genauer nachgucken.

    PS: Man merkt - ich habe mich bei der Registrierung verschrieben. 😞



  • fcom und vielleicht noch fstsw und sahf werden wohl die Befehle sein, nach denen du suchst.

    Zu deinem Benutzernamen: Schreib mal eine Mail an Marc++us. Wenn er gerade etwas Zeit hat, aendert er vielleicht deinen Benutzernamen.



  • Das mir printf immer -0,00000 ausgibt ist erstmal nicht so wichtig.

    Das ist sehr wichtig, denn die printf-Funktion kann meines Wissens keine floats ausgeben, nur doubles - und das hat Auswirkung wie man die Parameter auf dem Stack ablegt. Die 8 Bytes eines doubles muss man unter Beachtung der "Endianesses" auf dem Stack ablegen, ungefähr so:

    tmp: .double 0.0
    ...
    ftspl tmp
    movl (tmp + 4), %eax
    pushl %eax
    movl tmp, %eax
    pushl %eax
    

    Damit wäre eine double-Variable tmp auf dem Stack, etwas unschön gemacht, schöner wäre z.B. so:

    fstpl (%esp)
    

    Das war's.
    Was in deinem Code-Ausschnitt noch fehlt, ist die Bereinigung vom Stack, machst lauter push, aber kein einziges pop, in dem kurzen Code ist das vielleicht nicht so kritisch, später aber, wenn es umfangreich wird und du dich wunderst, warum bekomme ich ständig Stack-Overflows...
    Ansonsten hast du coole Sache gemacht, 1.0 + 2.0 auf Pentium 4 berechnet, warum auch nicht, weiter so 😉


Anmelden zum Antworten