Inline Assembler, bad immediate value for offset

L I V E Stammtisch ab 20:30 Uhr im Chat
  • Hallo,

    ich bin jetzt auf ein neues Problem beim Inline-Assembler gestoßen. Im Assembler-Code ist ein Block drin der oft wiederholt wird. Wenn die Anzahl der Wiederholungen eine gewisse Größe überschreitet (z.B. 400) dann meldet der Assembler einen Fehler "bad immediate value for offset(4980)".


    1. Frage: Wie kommt das und wie kann man es verhindern? Muss ich dem C-Compiler noch irgendwie mitteilen wie lang der Inline-Assembler-Code ist?

    2. Frage: Ich meine dass ich in diesem Fall keine Clobber-List brauche, weil außer den bereits deklarierten Variablen i1, i2 und sad nichts verändert wird. Ist das richtig?

    3. Frage: Die Zeiger ptr1 und ptr2 sind als Eingänge deklariert, werden allerdings auch durch den Code verändert. Ist das so richtig, oder müsste ich sie auch als Ausgänge deklarieren?

    Gruß
    Michael

  • Warum tust du dir eigentlich Assembler an? Und vor allem *wenn* du das schon tust, warum dann inline, mit der ja eher unangenehmen Syntax, statt gleich .S-Dateien zu schreiben, die dann kompiliert werden, vom GCC oder NASM?

    Wie dem auch sei: x86-Assembler hat mich nie interessiert, aber ich kenne sowohl vom 68K als auch diversen anderen Architekturen die Eigenschaft von Befehlen, dass sie fuer sogenannte immediate-Argumente (also Konstanten) aufgrund des Befehlsaufbaus nur eine beschraenkte Menge an Bits zur Verfuegung stellen. Koennten zB in deinem Fall 12 Bit sein, wo dann bei 4096 Schluss ist. Das sollte der Dokumentation der verwandten Instruktion entnehmbar sein.

    Wenn man mehr will, muss man zB statt einem immediate add ein load in ein register durchfuehren, und das addieren. Ich ueberlasse solche Fummeligkeiten ja lieber dem C/C++-Compiler :)
    Automatisch zusammengefügt:
    Nachtrag: das ist natuerlich nicht x86, sondern ARM - aber auch damit hab' ich bis dato keine Erfahrung :)
    Automatisch zusammengefügt:
    Und noch ein Nachtrag: fuer mich passiert das im uebrigen auch nicht. Ich hab' gerade .repr auf 10000 gestellt, und das disassembly zeigt mir auch -alles drin, alles dran. Ggf. hast du eine andere Compiler-Version oder Optionen (ich hab 5.2.1-22ubuntu2, und einfach "gcc -o test test.c" verwandt), und da wird anderer Code generiert. Ggf. mal schauen, wie ein diff zwischen zwei verschiedenen Wiederholungsraten aussieht, und ggf. sieht man da, das eine Sprungmarke immediate ist, und ueberlaeuft.


  • Warum tust du dir eigentlich Assembler an?
    ...

    Wenn man mehr will, muss man zB statt einem immediate add ein load in ein register durchfuehren, und das addieren. Ich ueberlasse solche Fummeligkeiten ja lieber dem C/C++-Compiler :)

    Es gibt eben Anwendungen, wo man die größte mögliche Geschwindigkeit braucht, und wo das mit C nicht so schnell geht. Wie z.B. Sum_of_absolute_Differences. Ich wüsste nicht wie ich den C Compiler dazu bringen soll dass er diesen Assembler-Befehl verwendet. Der gleiche Algorithmus in C programmiert würde mindestens 10 mal mehr Laufzeit brauchen.

    Zum zweiten Punkt: Klar, es gibt Befehle die nur einen eingeschränkten Wertebereich zulassen. In diesem Fall wird der Fehler aber nicht von meinem Inline-Assembler Code erzeugt. Da ist nämlich gar kein Befehl drin der diesen Fehler erzeugen könnte. Meiner Meinung nach kann der Fehler nur aus dem Teil kommen, der vom C Compiler erzeugt wurde. An welcher Stelle der Fehler nun genau auftritt, das weiss ich noch nicht.

    Gruß
    Michael
    Automatisch zusammengefügt:


    (ich hab 5.2.1-22ubuntu2, und einfach "gcc -o test test.c" verwandt)

    Ich verwende den gcc der bei Raspbian/Jessie mit dabei war. Aufruf mit gcc test.c

    Einmal editiert, zuletzt von maus3333 (3. Juli 2016 um 20:22)


  • Und vor allem *wenn* du das schon tust, warum dann inline, mit der ja eher unangenehmen Syntax, statt gleich .S-Dateien zu schreiben, die dann kompiliert werden, vom GCC oder NASM?

    Ich habe noch nicht herausgefunden wie die Parameter von C an die Assembler-Funktion übergeben werden, daher arbeite ich im Moment noch mit dem Inline-Assembler.


  • Ich verwende den gcc der bei Raspbian/Jessie mit dabei war. Aufruf mit gcc test.c

    Gut, das ist jetzt nicht wirklich ausreichend um zB nach einem Changelog zu suchen. gcc --version hilft dem ab.

    Wenn du dich rantasten willst an das Problem - gcc -S test.c liefert dir den Assembler-Output, dann kannst du mal schauen, wo's kracht.


  • Wenn du dich rantasten willst an das Problem - gcc -S test.c liefert dir den Assembler-Output, dann kannst du mal schauen, wo's kracht.

    Das ist ja ein Ding. Wenn ich den gcc so aufrufe, dann krige ich auch keine Fehlermeldung und das Programm läuft!
    Ich hatte den folgenden Aufruf verwendet, um ein gemischtes C/Assembler Listing zu erzeugen, und dann kommt die Fehlermeldung.
    gcc -Wa,-adhln test.c > assembly.s

    Gruß
    Michael

  • Es war wohl schon zu spät gestern Abend. Ich muss etwas richtig stellen:
    Wenn man gcc mit der Option -S aufruft, dann wird _nur_ das Assembler Listing erzeugt, und kein ausführbares Programm. Daher kommt auch keine Fehlermeldung.
    Der beschriebene Fehler kommt dadurch zustande, dass der C Compiler eine Abschätzung macht wie lang der Inline-Assembler Teil ist. Diese Abschätzung basiert auf der Anzahl der Code-Zeilen, und versagt daher wenn der Code "rept" Anweisungen enthält, die ihn wesentlich länger machen als er aussieht.
    Das Problem ist bekannt und im gcc Manual auf Seite 526-527 beschrieben:
    https://gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc.pdf
    In meinem Fall war im Assembler-Code an einer Stelle _vor_ dem Inline-Assembler Code ein Bezug auf ein Label das sich _hinter_ dem Inline-Assembler Code befand, und somit zu weit entfernt.

    Teil 1 meiner Frage ist somit erledigt.

    Gruß
    Michael

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!