Forum: Compiler & IDEs Disassembly, mapfile, PROGMEM


von Tom (Gast)


Lesenswert?

Hallo Forengemeinde,

ich habe bisher ein bisschen Grundlagen mit AVR ATmegas in C gemacht.
Heute habe ich mir mal das Manual zur avrlibc angesehen, insbesondere zu 
PROGMEM.

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_rom_array
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

Dabei taucht mehrfach der Hinweis auf das Disassembly der Objektdatei 
und die Mapdatei auf. Ich denke, es ist an der Zeit ein bisschen tiefer 
in die Materie vorzudringen und ein wenig Assembler zu lernen. Dann kann 
man sich verschiedene Code-Konstrukte ansehen und entscheiden, was 
effizienter umgesetzt wird.

Allerdings finde ich da den Einstieg nicht leicht und ich habe direkt 
ein paar Fragen:

1) Wie komme ich an das disassembly und das mapfile? (makefile?)
2) Kann ich mir die mit nem ganz normalen Editor angucken?
3) Wie interpretiert man ein Mapfile?
4) Woran erkenne ich, ob eine Variable jetzt nur im RAM oder auch im ROM 
liegt?

Ich möchte gerne die PROGMEM Beispiele (richtig/falsch) nachvollziehen.

Ich hoffe, ihr könnt mir beim Einstieg ein wenig helfen.
Danke.

Gruß
Tom

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tom schrieb:
> 1) Wie komme ich an das disassembly und das mapfile? (makefile?)

http://www.rn-wissen.de/index.php/Assembler-Dump_erstellen_mit_avr-gcc

In dein Makefile einbauen musst du selbst (wenn's sowas nicht schon 
hat).

> 2) Kann ich mir die mit nem ganz normalen Editor angucken?

Mit einem Text-Editor ja, mit einem Grafik-Editor wird's schwierig.

> 3) Wie interpretiert man ein Mapfile?

Ersma eins lesen und dann nachfragen, was unklar ist.

> 4) Woran erkenne ich, ob eine Variable jetzt nur im RAM oder auch im ROM
> liegt?

http://www.rn-wissen.de/index.php/Avr-gcc/Interna#Sections

von Tom (Gast)


Lesenswert?

Danke.
Werde es mir ansehen und ggf weiter frage.

von Tom (Gast)


Lesenswert?

Die angegebenen Seiten erklären das sehr schön.
Noch mal danke für den Hinweis!

Aber ich habe da noch eine kleine Frage.

Ich habe ein Standard makefile aus WINavr etwas ergänzt um auch eine 
Ausgabe in % und der .o Dateien zu erhalten:
----------------------------------------------------------
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
ELFSIZE = $(SIZE) --target=elf32-avr $(TARGET).elf
#
MYSIZE1 = $(SIZE) --mcu=$(MCU) -C $(TARGET).elf
MYSIZE2 = $(SIZE) $(OBJ)
MYSIZE3 = $(NM) --size-sort --print-size $(PROJECTNAME).elf
#Siehe: 
http://www.rn-wissen.de/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc

sizebefore:
  @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); 
$(ELFSIZE); \
  2>/dev/null; echo; fi

sizeafter:
  @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); 
$(ELFSIZE); \
  echo ; $(MYSIZE1); $(MYSIZE2); \
  2>/dev/null; echo; fi
----------------------------------------------------------

Zum Ausprobieren habe ich jetzt eine globale Variable angelegt einmal 
mit und einmal ohne Initialisierung und dann noch mit PROGMEM.
Dabei habe ich mir immer angeguckt, welcher Sectionbereich sich 
verändert.
Die Variable habe ich nicht weiter benutzt, nur die angegebene 
Deklaration.

----------------------------------------------------------
Keine Änderung der Datei

führt zu:

Size after:
   text     data      bss      dec      hex  filename
  17176       94     2178    19448     4bf8  can_debugger.elf

AVR Memory Usage
----------------
Device: at90can128

Program:   17270 bytes (13.2% Full)
(.text + .data + .bootloader)

Data:       2272 bytes (55.5% Full)
(.data + .bss + .noinit)


   text     data      bss      dec      hex  filename
    756       19        9      784      310  ./main.o
----------------------------------------------------------
----------------------------------------------------------

uint8_t testArray[20];

führt zu:

Size after:
   text     data      bss      dec      hex  filename
  17176       94     2198    19468     4c0c  can_debugger.elf

AVR Memory Usage
----------------
Device: at90can128

Program:   17270 bytes (13.2% Full)
(.text + .data + .bootloader)

Data:       2292 bytes (56.0% Full)
(.data + .bss + .noinit)


   text     data      bss      dec      hex  filename
    756       19        9      784      310  ./main.o

----------------------------------------------------------
----------------------------------------------------------

uint8_t testArray[20] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};

führt zu:

Size after:
   text     data      bss      dec      hex  filename
  17176      114     2178    19468     4c0c  can_debugger.elf

AVR Memory Usage
----------------
Device: at90can128

Program:   17290 bytes (13.2% Full)
(.text + .data + .bootloader)

Data:       2292 bytes (56.0% Full)
(.data + .bss + .noinit)


   text     data      bss      dec      hex  filename
    756       39        9      804      324  ./main.o
----------------------------------------------------------
----------------------------------------------------------

uint8_t testArray[20] PROGMEM = 
{0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};

führt zu:

Size after:
   text     data      bss      dec      hex  filename
  17196       94     2178    19468     4c0c  can_debugger.elf

AVR Memory Usage
----------------
Device: at90can128

Program:   17290 bytes (13.2% Full)
(.text + .data + .bootloader)

Data:       2272 bytes (55.5% Full)
(.data + .bss + .noinit)


   text     data      bss      dec      hex  filename
    776       19        9      804      324  ./main.o
----------------------------------------------------------

Fall 2) ohne Initialisierung führt wie erwartet zur Erhöhung von .BSS.
Jedoch ist dies im .o File von main nicht zu sehen.
Woran liegt das? Es müsste hier doch schon bekannt sein, dass keine 
Initialisierung stattgefunden hat.

Fall 3) mit Initialisierung vergrößert wie erwartet .DATA.
Aber warum wird .TEXT nicht erhöht, obwohl doch die 
Initialisierungswerte im Flash stehen müssten?

Bei Fall 4) mit PROGMEM landet alles erwartungsgemäß in .TEXT, also im 
Flash.

Ich hoffe das kann mir jemand anschaulich erklären.
Danke.

Gruß
Tom

von Stefan E. (sternst)


Lesenswert?

Tom schrieb:
> Fall 2) ohne Initialisierung führt wie erwartet zur Erhöhung von .BSS.
> Jedoch ist dies im .o File von main nicht zu sehen.
> Woran liegt das? Es müsste hier doch schon bekannt sein, dass keine
> Initialisierung stattgefunden hat.

Keine Ahnung. Sicher, dass du da nicht selber mit den ganzen Varianten 
und Ausgaben durcheinander geraten bist?

Tom schrieb:
> Fall 3) mit Initialisierung vergrößert wie erwartet .DATA.
> Aber warum wird .TEXT nicht erhöht, obwohl doch die
> Initialisierungswerte im Flash stehen müssten?

Sie stehen aber nicht in .text, sondern in .data. Sie landen letztlich 
im Flash, weil dann beide Sections (.text und .data) ins HEX-File 
geschrieben werden. Deswegen taucht .data bei der size-Ausgabe in beiden 
Zeilen auf:
1
Program:   17290 bytes (13.2% Full)
2
(.text + .data + .bootloader)
3
4
Data:       2272 bytes (55.5% Full)
5
(.data + .bss + .noinit)

von Tom (Gast)


Lesenswert?

Bei Fall 3) gebe ich dir Recht. Das habe ich übersehen.

Aber bei Fall 2) bin ich mir mit der angezeigten Ausgabe sicher.
Das muss einen anderen Grund haben.

von Stefan E. (sternst)


Lesenswert?

Tom schrieb:
> Aber bei Fall 2) bin ich mir mit der angezeigten Ausgabe sicher.
> Das muss einen anderen Grund haben.

Ok, habe es jetzt selber mal ausprobiert. Es liegt daran, dass der 
Compiler die Variable im common-storage platziert. Erst der Linker 
verfrachtet sie dann nach .bss. Du kannst beim Compilieren die Option 
-fno-common angeben, dann landet sie gleich in .bss, und du bekommst die 
entsprechende Ausgabe.

von Tom (Gast)


Lesenswert?

Danke für die Antwort.
Habe ich durch die Compileroption irgendwelche Nachteile?

von Stefan E. (sternst)


Lesenswert?

Tom schrieb:
> Habe ich durch die Compileroption irgendwelche Nachteile?

Nein.
Im Gegenteil, ohne die Option wird eine bestimmte Unsauberkeit beim 
Programmieren verdeckt (mehrfach Definitionen von Variablen in 
unterschiedlichen Modulen). Mit der Option führt das zu einem Fehler.

von Tom (Gast)


Lesenswert?

Dann sollte das doch eigentlich besser standardmäßig aktiviert sein...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Naja, das würde aber das ABI verädern, und dafür gibt es mM keinen 
Grund.

Es wird davon ausgegangen, daß der Anwender die Doku gelesen hat und 
sich über die verwendeten (oder nicht-verwendeten) Schalter im Klaren 
ist. Es ist auch keine Optimierungs-Option, sondern beeinflusst die 
Datenablage.

von Tom (Gast)


Lesenswert?

Kann man das mit der Zwischenplatzierung im "common storage" irgendwo 
sehen, oder ist das einfach "Wissen"?

Ich habe Beispiel 2) ohne Initialisierung und Beispiel 3) mit 
Initialisierung noch ein mal durchprobiert und nach dem Arraynamen 
gesucht:

Fall 2)
                      .bss           0x0080015e       0x1d main.o
                                     0x0080015e                f_timer
can_debugger.map:645:                0x0080015f                testArray
can_debugger.map:1300:testArray 
main.o
can_debugger.sym:462:0080015f B testArray
main.c:86:uint8_t testArray[20];
main.lst:590: 623                 .global  testArray
main.lst:591: 624                 .global  testArray
main.lst:593: 628                 testArray:
main.lst:627:C:\Users\XXX\AppData\Local\Temp/cckot7Sf.s:628 
.bss:00000001 testArray
main.s:659:.global  testArray
main.s:660:.global  testArray
                .section .bss
main.s:662:  .type  testArray, @object
main.s:663:  .size  testArray, 20
main.s:664:testArray:
                .skip 20,0
          .section  .debug_frame,"",@progbits
main.s:1463:  .long  testArray
main.s:2196:  .string  "testArray"
main.s:2988:  .string  "testArray"


Fall 3)
                      .data          0x00800100       0x27 main.o
can_debugger.map:583:                0x00800100                testArray
can_debugger.map:1300:testArray 
main.o
can_debugger.sym:450:00800100 D testArray
main.c:86:uint8_t testArray[20] = 
{0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};
main.lst:561: 580                 .global  testArray
main.lst:563: 584                 testArray:
main.lst:640:C:\Users\XXX\AppData\Local\Temp/ccGYR3Uj.s:584 
.data:00000000 testArray
main.s:612:.global  testArray
                .data
main.s:614:  .type  testArray, @object
main.s:615:  .size  testArray, 20
main.s:616:testArray:
  .byte  0
  .byte  1
  .byte  2
  .byte  3
  .byte  4
  .byte  5
  .byte  6
  .byte  7
  .byte  8
  .byte  9
  .byte  0
  .byte  1
  .byte  2
  .byte  3
  .byte  4
  .byte  5
  .byte  6
  .byte  7
  .byte  8
  .byte  9
main.s:1481:  .long  testArray
main.s:2214:  .string  "testArray"
main.s:3006:  .string  "testArray"


Daraus kann ich nur sehen, wo das Array am Ende landet. Nämlich einmal 
in .bss und einmal in .data. Oder sollten mir die Zeilen aus der main.s 
mehr sagen?

von Tom (Gast)


Lesenswert?

Ach mist, jetzt hatte ich noch die Option "CFLAGS += -fno-common" drin.
Ohne sieht man es in main.s:

status.1767:
  .byte  1
  .comm testArray,20,1
  .section  .debug_frame,"",@progbits

So viel Mühe gegeben und dann doch sinnlos gefragt. Sorry.

von Tom (Gast)


Lesenswert?

Interessanterweise steht es jetzt aber auch noch im MAP file in common:
 COMMON         0x00800199       0x14 main.o
                0x00800199                testArray

und in der .lst auch:
659                   .comm testArray,20,1

main.s:617    .bss:00000000 f_timer
                            *COM*:00000014 testArray

Da hätte ich jetzt irgendwo schon die Zuordnung zu .bss erwartet.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tom schrieb:
> Da hätte ich jetzt irgendwo schon die Zuordnung zu .bss erwartet.

Siehe Linker-Skript:
1
  .bss   : AT (ADDR (.bss))
2
  {
3
     PROVIDE (__bss_start = .) ;
4
    *(.bss)
5
    *(.bss*)
6
    *(COMMON)
7
     PROVIDE (__bss_end = .) ;
8
  }  > data

von Tom (Gast)


Lesenswert?

Wo finde ich das?
Was ist eigentlich .sys, .lss und .lst?
Danke!

von Tom (Gast)


Lesenswert?

Tom schrieb:
> .sys

.sym meinte ich...

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
Noch kein Account? Hier anmelden.