Aus den unterschiedlichsten Gründen kann es wünschenswert sein, den Assembler-Code zu sehen, den gcc avr-gcc (oder gcc im Allgemeinen) aus einer C/C++-Quelle erzeugt. Die Ausgabe von gcc geschieht immer in Form von ASCII als Assembler-Datei. Ohne die Angabe spezieller Optionen ist diese Assembler-Datei jedoch nur temporär und wird nach Beenden der von gcc aufgerufenen Programme cc1, as und ld wieder gelöscht.
Ein Weg, den zu einer Quelle gehörenden Assembler-Code zu erhalten ist also, diese temporäre Datei zu erhalten, was mit der gcc-Option -save-temps geschieht, oder indem man nur assembliert, was mit der Option -S geschieht.
Alternativ dazu kann man durch objcopy ein Disassemble der erzeugten Objekte erzeugen.
Ja nach dem, welchen dieser Möglichkeiten man wählt, enthält die Assembler-Ausgabe unterschiedliche Informationen, Darstellungen und Erläuterungen.
Als C-Beispiel dient eine kleine Funktion, die einem Foren-Beitrag zu selbigem Thema entstammt. Die Assembler-Dumps sind jedoch nur Snips der kleinen Funktion foo, um die es hier gehen soll. Für komplexere Funktionen oder andere gcc-Targets (etwa arm7-gcc) ist die Vorgehensweise analog. Die main-Funktion wird nur gebraucht, damit für das letzte Beispiel ein elf erzeugt werden kann, da hier gegen main gelinkt wird.
Inhaltsverzeichnis
C-Quelle
unsigned char command_rc5; unsigned char Ir_data_tmp; void foo() { uint8_t cmd = command_rc5 & ~(1<<7); if (Ir_data_tmp & (1<<5)) cmd |= (1<<7); command_rc5 = cmd; } int main main() { return 0; }
Compiler dumpt Assembler
Kein Assemblieren
Die Arbeit von gcc endet mit Schreiben der Assembler-Ausgabe. Es wird also auch kein Object (*.o) erzeugt.
Kommando:
> avr-gcc -S -fverbose-asm ...
Ausgabe:
.global foo .type foo, @function foo: /* prologue: frame size=0 */ /* prologue end (size=0) */ lds r25,command_rc5 ; cmd, command_rc5 andi r25,lo8(127) ; cmd, lds r24,Ir_data_tmp ; Ir_data_tmp, Ir_data_tmp sbrc r24,5 ; Ir_data_tmp, ori r25,lo8(-128) ; cmd, .L2: sts command_rc5,r25 ; command_rc5, cmd /* epilogue: frame size=0 */ ret /* epilogue end (size=1) */ /* function foo size 11 (10) */ .size foo, .-foo
mit Assemblieren
Wüschenswert wäre folgendes Kommando:
> avr-gcc -c -save-temps ...
Dies führt jedoch aus unerfindlichen Gründen zum Verlorengehen von Symbolen. Alternativ kann man zwei Aufrufe machen, was dummerweise etwas länger dauert und schwer in Makefile-Generatoren auszudrücken ist:
> avr-gcc -S -save-temps ... > avr-gcc -c ...
Die Ausgabe ist dann wie im vorherigen Abschnitt, nur daß jetzt auch assembliert wird.
Assembler dumpt Assembler (kein Assemblieren)
Kommando:
> avr-gcc -c -Wa,-alhd=dump.s ...
Ausgabe:
18 .global foo 20 foo: 21 .LFB2: 22 .LM1: 23 /* prologue: frame size=0 */ 24 /* prologue end (size=0) */ 25 .LM2: 26 0000 9091 0000 lds r25,command_rc5 27 0004 9F77 andi r25,lo8(127) 28 .LM3: 29 0006 8091 0000 lds r24,Ir_data_tmp 30 000a 85FD sbrc r24,5 31 .LM4: 32 000c 9068 ori r25,lo8(-128) 33 .L2: 34 .LM5: 35 000e 9093 0000 sts command_rc5,r25 36 /* epilogue: frame size=0 */ 37 0012 0895 ret 38 /* epilogue end (size=1) */ 39 /* function foo size 11 (10) */
objdump erzeugt Disassemble
aus Object (nicht loakatiert)
Kommando:
> avr-objdump -d -S ...
Ausgabe:
00000000 <foo>: uint8_t command_rc5, Ir_data_tmp; void foo() { uint8_t cmd = command_rc5 & ~(1<<7); 0: 90 91 00 00 lds r25, 0x0000 4: 9f 77 andi r25, 0x7F ; 127 if (Ir_data_tmp & (1<<5)) 6: 80 91 00 00 lds r24, 0x0000 a: 85 fd sbrc r24, 5 cmd |= (1<<7); c: 90 68 ori r25, 0x80 ; 128 command_rc5 = cmd; e: 90 93 00 00 sts 0x0000, r25 12: 08 95 ret
aus elf (lokatiert)
Kommando:
> avr-objdump -h -S ...
Ausgabe:
0000005c <foo>: uint8_t command_rc5, Ir_data_tmp; void foo() { uint8_t cmd = command_rc5 & ~(1<<7); 5c: 90 91 60 00 lds r25, 0x0060 60: 9f 77 andi r25, 0x7F ; 127 if (Ir_data_tmp & (1<<5)) 62: 80 91 61 00 lds r24, 0x0061 66: 85 fd sbrc r24, 5 cmd |= (1<<7); 68: 90 68 ori r25, 0x80 ; 128 command_rc5 = cmd; 6a: 90 93 60 00 sts 0x0060, r25 6e: 08 95 ret