Hallo, ich habe mir gerade ein ASM-Listing für einen Cortex M4F angeschaut, weil mich interessiert hat, ob eine "normale" C-Funktion in diesem Fall irgendeinen Nachteil gegenüber einer static inline-Funktion hat. Das Assembler-Listing ist im Anhang. Dabei aufgefallen sind mir zwei NOP-Instruktionen, deren Zweck ich nicht verstehe, nämlich die Zeilen 62 und 68. Mein erster naiver Gedanke war, dass das NOP in Zeile 62 dafür da gewesen wäre, das erste WORD an einer durch 4 teilbaren Adresse auszurichten - aber dann wäre das zweite NOP in Zeit 68 nicht da, sondern das WORD danach zwei Zeilen früher. Und warum ein NOP? Warum nicht ein SHORT 0? Jetzt bin ich verwirrt. Wer kann mich aufklären?
Anscheinend arbeitet der Optimizer noch nicht perfekt. Der könnte zwar beide nop vermeiden, wenn er den Speicherplatz für die Konstanten vertauscht. Hat aber noch niemand implementiert.
Das habe ich auch in Assemblern gehabt, es wird ein 16 Bit Sprung vorgesehen da das Sprungziel nicht bekannt ist, aber später mit einem 8 Bit Sprung ausgeführt wird. Da wird nicht genügend Optimiert.
NOP wird verwendet, weil der dies einfügende Assembler oder Linker sich dann nicht darum kümmern muss, ob es ein Daten- oder Codebereich ist.
1 | 80074f4: 30767264 .word 0x30767264 |
2 | 80074f8: 696e695f .word 0x696e695f |
3 | 80074fc: 0074 .short 0x0074 |
4 | 80074fe: bf00 nop |
5 | 8007500: ff00000c .word 0xff00000c |
Das sind Daten, keine Befehle. Das erste dürfte der String "drv0_init\0" sein. Wofür die weiteren 0x00 0xbf 0x0c 0x00 0x00 0xff sind, erschließt sich mir so direkt nicht.
Jörg W. schrieb: > 0x00 0xbf 0x0c 0x00 0x00 0xff Nur 0xbf 0x0c 0x00 0x00 0xff Weil der 0x00 am anfang noch zu dem String gehört. Null terminated string brauch am ende den 0, sonst weiss man nicht wo es endet. Der NOP kann dann wegen aligment da sein.
Andras H. schrieb: > Nur 0xbf 0x0c 0x00 0x00 0xff > Weil der 0x00 am anfang noch zu dem String gehört. Nö, die 0 dafür steht bereits auf 0x80074fd. Die auf 0x80074fe ist was anderes. Beachte, dass die Zahlendarstellung der Strings little-endian ist, was die Zeichenfolge "unlogisch" herum dreht. (Das war ja letztlich der Vorteil von big-endian, es ist egal, ob man auf die Zahlengruppen in 8, 16 oder 32 Bit draufschaut, sie sehen immer gleich angeordnet aus.)
Jörg W. schrieb: > Das erste dürfte der String "drv0_init\0" > sein. Alle Achtung, dass Du das im Kopf siehst. Ich habe mir gerade erstmal ein Skript geschrieben, um das zu prüfen. So sehen also Debug-Symbole aus. Wieder etwas gelernt. Was mich gerade richtig ärgert ist, dass ich mir die Frage danach vorher noch nie gestellt habe.
Walter T. schrieb: >> Das erste dürfte der String "drv0_init\0" >> sein. > > Alle Achtung, dass Du das im Kopf siehst. Die Vermutung, dass da ASCII-Zeichen stehen, war mir tatsächlich beim Anblick solcher Zahlen gekommen. Für den String selbst habe ich dann aber schon eine ASCII-Tabelle genommen. ;-) Reine Debugsymbole wandern eigentlich nicht ins Binary hinein, also nicht in den in den Flash geladenen Teil. Da musst du irgendwas in deinem Code drin haben, was den Funktionsnamen als String reinzieht (den bekommt man in C ja über einen vom Standard definierten Makro geliefert).
Wie habe ich eine Chance herauszubekommen, was das ist? Die Funktionen selbst können es nicht sein - in der zitierten Funktion ist nichts derartiges. Dort wird nur eine globale Variable in eine andere globale Variable kopiert. Keine Fehlerbedingung, keine Assertion. Praktisch ist das nicht so wichtig. Ich habe noch viel, viel Flash übrig. Aber neugierig bin ich schon.
Schwierig von der Ferne zu sagen. Irgendwer muss den String ja referenzieren, aber ob man das im Disassembly so direkt erkennt? Hast du sowas wie assert() benutzt?
Das sind keine Debug Symbole - die landen wie schon erwähnt nicht im flash - sondern eher Debugging Code analog zu
1 | void drv0_init() |
2 | {
|
3 | printf("drv0_init"); |
4 | }
|
Die Strings müssen im Flash relativ dicht bei der verwendenden Funktion liegen wenn man deren Adresse mit einem einzigen 16-Bit Befehl laden möchte.
Ich finde zumindest nichts im Disassembly, was 0x80075aXX lädt. assert()/error() nutze ich - nicht in dieser Funktion, aber in dieser .c-Datei. Gäbe es "verdächtige" Compiler-Optionen? Das Flag "-G3" war es auf jeden Fall nicht. Einen Modultest zu dieser Funktion gibt es auch nicht. Aber die Funktionsnamen jeder Funktion liegen tatsächlich als Zeichenkette im Flash.
Kannst du den Sourcecode der Funktion (und ggf. die Compileroptionen) denn hier posten?
"Sicher, an meinen Spielereien ist nichts geheim." - wollte ich gerade posten. Aber in der Vorbereitung, das Build-Log ein wenig von langweiligen Dateilisten zu säubern, damit es überhaupt zumutbar ist, dort hineinzuschauen, habe ich den "Übeltäter" gefunden: "-mpoke-function-name" Ich habe nur nicht mehr die geringste Ahnung, warum ich das wohl aktiviert habe und was ich mir davon versprochen habe. Da heisst es wohl, handschriftliche Notizen zu durchsuchen. :-(
Interessant, kannte ich noch gar nicht. Schön, dass du's auf diese Weise gefunden hast.
Ansonsten auch mal mit -S oder --save-temps compilieren und sich das generierte <foo>.s anschauen. Dann sieht man, was der Compiler generiert hat und nicht das, was Assembler und Linker daraus gemacht haben bzw der Disassembler sich zusammengereimt hat. Bei den NOPs z.B. könnte da ein ".align irgendwas" stehen.
Beitrag #7229723 wurde von einem Moderator gelöscht.
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.