Disassembly, mapfile, PROGMEM

Gast #2263791
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
Persönliche Seite #2263818
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
Gast #2267627
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
#2267642
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)
#2267889
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.
Gast #2271591
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?
Gast #2271601
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.
Gast #2271605
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren