Hallo,
zum Überprüfen von meinem Programm würde ich gern mal den vom
C-Compiler generierten ASM-Code anschauen, und zwar nachdem der
Präprozessor die Defines berechnet und ersetzt hat, die Kommentare raus
gestrippt wurden usw.
Das .lss File ist ja ein Anfang, aber da sind die Kommentare alle noch
drin, die Defines noch nicht ersetzt.
Gibt es eine Möglichkeit ein List-File zu erhalten, das zumindest die
Defines alle schon "in endgültiger Schreibweise" ersetzt drin hat? So
könnte man mal überprüfen ob alles so evaluiert, wie man sich das
erhofft.
Ich verwende AVR-Studio 4.18sp1 und AVR-GCC 20090313
Zur Not kann ich auch mit der Kommandozeile umgehen, aber direkt aus
AVR-Studio wäre natürlich bequemer...
Gruß
Fabian
Füge den Compiler-Optionen ein -save-temps hinzu. Dann hast du im
Build-Ordner ("default" falls du keinen eigenen Namen angegeben hast)
nach dem Build zu jeder C-Datei eine i-Datei und eine s-Datei. Ersteres
ist der Präprozessor-Output, letzteres der vom Compiler generierte
ASM-Code.
Hey, Danke. Da hab ich erstmal was zum forschen.
Wird das .lss-File eigentlich nach oder vor dem .i und .s erstellt? Im
.i schaut's nämlich gut aus, im .lss hingegen ist der Code an manchen
Stellen wie vermischt, zumindest wenn der darstellte ASM-Code was mit
den drüber stehenden C-Zeile zu tun hat. Da ist die Abschlusschleife (})
eines If schonmal erst nach dem nächsten If-Block, obwohl die sonst
getrennt und nacheinander stehen sollten.
Gruß
Fabian
Fabian B. schrieb:
> Wird das .lss-File eigentlich nach oder vor dem .i und .s erstellt?
Das lss-File wird erstellt, wenn der eigentliche Build-Prozess komplett
abgeschlossen ist. Das lss-File ist disassemblierter Objektcode, in den
mit Hilfe der Debug-Infos der ursprüngliche C-Code "eingemischt" wird.
Da durch das Optimieren aber häufig kein eindeutiger 1:1 Zusammenhang
mehr zwischen C und ASM-Code besteht, klapp das oft nicht besonders gut.
Demnach darf man sich also auf die Darstellung (Zuordnung C zu ASM) dort
nicht verlassen? Das Programm "kann" also funktionieren, obwohl der Code
mit Zuordnung im .lss nicht unbedingt Sinn macht?
Noch eine Frage zum Präprozessor hätte ich noch:
gibt es irgendwo eine "einfache" Möglichkeit zu sehen, zu welchem Wert
Defines evaluieren? Sowas wie eine Übersicht Define->Wert?
Gruß
Fabian
Mist, jetzt ist schon zu spät zum editieren des letzten Posts.
Mathematische (bzw. logische) Ausdrücke aus Konstanten werden ja vom
Compiler, nicht vom Präprozessor berechnet.
Ich habe den Ausdruck
ID = ((U16)(NID_CONFIG << 7) & (U16)EXT_BIT_MSK) & (U16)ownID;
ID ist eine U16, NID_CONFIG ist ein Define mit dem Wert 0x07 und
EXT_BIT_MSK ist ein Define mit dem Wert 0x40. ownID ist eine U8
Variable.
Wird der vordere Teil des Ausdrucks zur Kompilezeit schon berechnet und
als Konstante im Code abgelegt?
Im .lss-File ist das leider nicht annähernd mehr zu erkennen, im .i ist
es noch nicht evaluiert und im .s ist das nicht zu finden...
Gibt es noch ein temp-File vom Compiler, wo solche Ausdrücke schon
verarbeitet sind, der Code aber noch erhalten?
Gruß
Fabian
> Demnach darf man sich also auf die Darstellung (Zuordnung C zu ASM) dort> nicht verlassen? Das Programm "kann" also funktionieren, obwohl der Code> mit Zuordnung im .lss nicht unbedingt Sinn macht?
Richtig, sofern Optimierungen an sind. Nach ISO-C ist es so, daß der
Compiler beliebige Änderungen machen, sofern das "beobachtbare
Verhalten" das gleiche ist. Das beobachtbare Verhalten ist dabei
definiert durch I/O und den Zugriff auf volatile-Variablen. Diese
Vorgabe macht sich GCC zunutze und sortiert Teile des Code um,
kombiniert welche oder entfernt sie ganz, sofern das am Ergebnis nichts
ändert.
> gibt es irgendwo eine "einfache" Möglichkeit zu sehen, zu welchem Wert> Defines evaluieren? Sowas wie eine Übersicht Define->Wert?
Meinst du da nur eine einfach Liste aller Makros?
Das ginge etwa so:
1
cpp -dM datei.c
Oder willst du deinen Quellcode sehen, so wie er nach dem Präprozessor
aussieht? Dann kannst du ihn einfach durch den Prärozessor laufen
lassen:
1
cpp datei.c
Mit -dD bekommst du übrigens beides. Wenn du eine schon vorhandene
gcc-Kommandozeile nutzen willst, kannst du statt cpp einfach gcc -E
machen und die obigen Optionen anhängen. Nicht vergessen, evtl. ein -o
foo.o zu entfernen, sonst schreibt er die Ausgabe da rein.
> Mathematische (bzw. logische) Ausdrücke aus Konstanten werden ja vom> Compiler, nicht vom Präprozessor berechnet.
Größtenteils, ja.
Ich habe den Ausdruck
ID = ((U16)(NID_CONFIG << 7) & (U16)EXT_BIT_MSK) & (U16)ownID;
> Wird der vordere Teil des Ausdrucks zur Kompilezeit schon berechnet und> als Konstante im Code abgelegt?
Mit eingeschalteten Optimierungen normalerweise ja, aber nicht vom
Präprozessor.
> Im .lss-File ist das leider nicht annähernd mehr zu erkennen, im .i ist> es noch nicht evaluiert und im .s ist das nicht zu finden...
Vermutlich wegoptimiert. Möglicherweise macht er die Berechnung erst
irgendwann später, wenn ID dann benutzt wird. Wenn ID nachher nicht
benutzt wird, kann's auch sein, daß die Berechnung komplett entfernt
wird.
> Gibt es noch ein temp-File vom Compiler, wo solche Ausdrücke schon> verarbeitet sind, der Code aber noch erhalten?
Kann schon sein, aber dann vermutlich nicht als C- oder Assembler-Code,
sondern als Syntaxbaum.
Ja, Optimierung steht auf -Os.
Ich hatte nur gehofft, dass es noch sowas wie das .s-File gibt, nur halt
mit diesen Ausdrücken aufgelöst, soweit wie der Compiler das halt macht.
Wegoptimieren dürfte er diese Zeile eigentlich nicht, weil dann die
Anweisungen danach unsinnig würden.
Aber im .lss-File ist ja eh nix aufgelöstes, sondern da stehen ja wieder
die Defines mit ihren Symbolen.
Gruß
Fabian
Fabian B. schrieb:
> Ja, Optimierung steht auf -Os.> Ich hatte nur gehofft, dass es noch sowas wie das .s-File gibt, nur halt> mit diesen Ausdrücken aufgelöst, soweit wie der Compiler das halt macht.
Gibt es auch, aber glaub' mir, das willst du nicht unbedingt
verstehen. ;-) Du kannst ja spaßeshalber mal die Option -da
ausprobieren...
Fabian B. schrieb:
> Aber im .lss-File ist ja eh nix aufgelöstes, sondern da stehen ja wieder> die Defines mit ihren Symbolen.
Es steht darin der C-Code und darunter der generierte Assembler.
Und der Assembler enthält ja dann die Werte als Hex (Kommentar Dezimal)
in den LDI, CPI usw. Befehlen.
Peter
Okay, vielleicht häng ich gedanklich auch einfach etwas, aber Assembler
ist mir an sich schon geläufig.
Etwas abweichend von oben:
Struct Variable tx_temp mit member .cmd als ein ENUM von vier möglichen
Werten, .id.std vom Typ U16 und .dlc vom Typ U8 (und noch ein paar
mehr). Im .lss steht nun beim Befüllen der Struct:
NID_CONFIG ist in diesem Fall 0x00 (define), EXT_BIT_MSK ist 0x40
(define), ownID ist eine U8 Variable.
Was mich nun wundert: das Y Register ist ja R28,R29. Dieses wird
nirgends in der Funktion vor diesen Befehlen beschrieben. Bei den
Befehlen davor kann ich die ASM-Anweisungen durchaus nachvollziehen.
Und bei der Zeile mit den Defines müsste von dem Ausdruck ja eigentlich
sowas wie (U16)(0x40 & ownID) übrig bleiben. Seh nur ich das in den zwei
Assembler-Anweisungen nicht (Zeile 192a, 192c)?
Vielleicht kann mich da jemand Erhellen. ;-)
Gruß
Fabian
Fabian B. schrieb:
> NID_CONFIG ist in diesem Fall 0x00 (define)
Dann ist jede Verundung damit auch 0 und damit ist Laden mit R1
(Nullregister) korrekt.
> Was mich nun wundert: das Y Register ist ja R28,R29. Dieses wird> nirgends in der Funktion vor diesen Befehlen beschrieben.
Vielleicht vom Aufrufer.
Peter
Wenn du alle defines loswerden möchtest, kompilier mal mit -E . Damit
wird nur der Präprozessor ausgeführt. Schreib den output in ein neues
C-File, und lass das dann normal compilieren. Damit bekommst du ein
Assemblerlisting mit aufgelösten #defines (Aber dann ALLEN). Schön ist
aber anders...
Oliver
ARGL
Das kommt davon wenn man zu später Stunde ohne ausreichend Kaffee
programmiert... das müsste natürlich ein | (oder) sein.
Jetzt macht das .lss auch Sinn!