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
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
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
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) |
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.
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.
Danke für die Antwort. Habe ich durch die Compileroption irgendwelche Nachteile?
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.
Dann sollte das doch eigentlich besser standardmäßig aktiviert sein...
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.
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?
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.
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.
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 |
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.