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
aus ihex (lokatiert)
Siehe auch