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
zeig uns doch man den asm code, evnetuell sehe ja andere wie die berechnung gemacht wird
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:
1 | tx_temp.cmd = CMD_TX; |
2 | 1928: 9a 83 std Y+2, r25 ; 0x02 |
3 | // ID und Mask setting für BusDiscoveryReply |
4 | tx_temp.id.std = ((U16)(NID_CONFIG << 7) & (U16)EXT_BIT_MSK) & (U16)ownID; // Nur Ext-Bit gesetzt |
5 | 192a: 1c 82 std Y+4, r1 ; 0x04 |
6 | 192c: 1b 82 std Y+3, r1 ; 0x03 |
7 | |
8 | tx_temp.dlc = 1; // Länge der Nachricht = 1 |
9 | 192e: 9b 87 std Y+11, r25 ; 0x0b |
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!
1 | tx_temp.id.std = ((U16)(NID_CONFIG << 7) | (U16)EXT_BIT_MSK) | (U16)ownID; |
2 | 192c: 80 64 ori r24, 0x40 ; 64 |
3 | 192e: 8b 83 std Y+3, r24 ; 0x03 |
4 | 1930: 1c 82 std Y+4, r1 ; 0x04 |
Unteres Byte wird die Maske und ownID, das obere 0x00 aus Null-Register. Gruß Fabian
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.