Fließkommazahlen handhaben



  • Hallo,

    ich benutze GNU Assembler gas unter Linux und möchte ein Paar Operationen mit Fließkommazahlen durchführen. Scheint alles gut zu funktionieren, nur eines gefällt mir dabei nicht: Möchte ich eine Zahl z.B. auf dem Stack ablegen, muss ich folgenden Weg gehen:

    .data
    meine_zahl: .single 1.2567
    .text
        movl meine_zahl, %eax
        movl %eax, (%esp)
    

    ...also einen Umweg über ein Register. Ist eigentlich nicht so schlimm, aber bei einem längerem Programm, schwindet die Lesbarkeit des Codes dahin.
    Und so würde ich es gerne machen:

    .text
        movl $1.2567, (%esp)
    

    Aber der GNU Assembler weigert sich, den Code zu assemblieren. Theoretisch sollten sich hier keine Probleme ergeben, denn die Fließkommazahl 1.2567 (als single betrachetet) ist 4 Byte lang und für das mov-Kommando spielt es keine Rolle, um welche 4 Bytes es sich handelt...

    Weiß jemand eine Abhilfe dafür?
    Ist es mit anderen Assemblern möglich, Fließkommazahlen direkt im Quellcode zu verwenden?
    Kann man das vielleicht durch irgendein Assembler-Parameter so einstellen, dass die Fließkommazahlen im Code durch ihre interne Darstellung als Integer interpretiert werden, also statt movl $1.2567, (%esp) z.B. als movl $0x12345678, (%esp) vom Assembler selbst ersetzt wird?
    Als workaround habe ich mir ein kleines lex-Programm erstellt, das genau das macht, den Assembler-Quellcode nach Fließkommazahlen zu durchsuchen und diese durch ihre interne Darstellung als Integer zu ersetzen.
    Beim Assemblieren gehe ich dann ungefähr so vor:
    *
    ./lex_programm mein_asm_program.s > tmp.s
    as tmp.s -o tmp.o
    ld tmp.o -o mein_prog
    *
    Schön ist das auch nicht...



  • ich hab grad folgendes ausprobiert:

    meine_zahl: .single 1.23
          pushl meine_zahl
          pushl $f0.1
          movl $f1.1,(%esp)
    

    die ersten zeilen sind denke ich mal klar.
    bei den zweiten beiden musste ich ein wenig rumfrikeln, bis der assembler nicht mehr gemeckert hat. weiß aber nicht, ob das so wirklich geht. musst du eben ausprobieren. siehe auch:
    http://www.cs.utah.edu/dept/old/texinfo/as/as.html#SEC33



  • Und so würde ich es gerne machen:

    movl $1.2567, (%esp)
    

    woher soll der assembler wissen, ob es sich um float oder double handelt?



  • kannst ja

    movl $f1.1, .double (%esp)
    # oder
    movl $f1.1, .float (%esp)
    

    schreiben



  • Hallo,

    vielen Dank für die Info.
    Habe versucht, den Code so auszuprobieren, bekomme allerdings Linker-Fehlermeldung undefined reference to f0.1.
    Folgenden Code mit as prog.s -o prog.o ausprobiert:

    movl $f0.1, (%esp)
        pushl $f0.1
    

    Wie es aussieht, erkennt gas nicht, dass es sich um eine Fließkommazahl handelt, sondern um eine Variable, siehe
    http://www.cs.utah.edu/dept/old/texinfo/as/as.html#SEC43
    Bestätigen kann man es, wenn man die Objektdatei prog.o disassembliert. objdump -d prog.o ergibt:

    movl $0x0, (%esp)
        pushl $0x0
    

    Zitat:
    woher soll der assembler wissen, ob es sich um float oder double handelt?

    ja, es stimmt, der Assembler kann es nicht wissen, ich dachte, vielleicht kann man irgendwie den Code so eingeben. Ich war halt ein wenig "müde", in einem Programm für jede Konstante einen Namen auszudenken. Im lex-Programm, das ich erwähnt habe, wird implizit davon ausgegangen, dass es sich um ein Float handelt.
    Also kann man z.B. folgendes schreiben:

    movl $1.0, (%esp)
        flds (%esp)
        movl $2.0, (%esp)
        flds (%esp)
        movl $2.1785, (%esp)
        flds (%esp)
        faddp ...
        ...
    

    Vielleicht wäre dieser Code kompakter und schneller:

    .text
        flds a
        flds b
        flds c
        faddp ...
        ...
    a: .single 1.0
    b: .single 2.0
    c: .single 2.1785
    

    Aber bei mehr Konstanten verliere ich schnell den Überblick, und weiss nicht, was war denn nun a oder b oder c, und wenn der code weiter unten steht, muss hin und her springen und schauen, wo sind sie denn deklariert...
    Was meint ihr dazu? Was ist so gängige Praxis?



  • lade die floats doch als immediate auf den fpu-tos - da gehoeren sie doch sowieso hin...



  • Als immediate meinst du etwa so:

    flds $1.0
    

    Ich bin jetzt ein wenig durcheinander... war irgendwie die ganze Zeit aus welchen Gründen auch immer überzeugt, dass es so nicht geht, werde mal in den Intel-Unterlagen nachschlagen...



  • man kann keine immediates in die FPU laden. das geht nur über den speicher. also so wie du das im letzten beispiel gemacht hattest, würde ich das auch machen. es könnte auch helfen, den variablen sinnvollere namen zu geben als nur a,b und c. außerdem gibt es noch befehle wie fld1, die oft benutzte zahlen in den TOS laden, hier ist es z.b. die 1.0 oder fldpi lädt die zahl $$\pi$$ .



  • ja, laut Intel-Doku kann man leider keine Immediates nach FPU-Register laden...


Anmelden zum Antworten