Hallo und frohe Ostern, Ich habe ein AVR Projekt aus C++ und Assembler Code. Zum Kompilieren und Linken verwende ich avr-gcc (via ArduinoMakefile). Die `main()` liegt im C++ Code. Kompiliert wird das für einen Atmega328p (old bootloader) auf einem Arduino. Das alles funktionierte auch wunderbar, solange der SRAM einigermaßen leer blieb. Mittlerweile brauche ich 75% und beobachte, dass der Stack in meine Variablen hineinwächst. Die weitere Untersuchung am Simulator ergab, dass in der assemblierten `main()` der Stackpointer umgesetzt wird. Während er Anfangs bei 0x08ff liegt, wird er auf signifikant weniger herabgesetzt. Ich frage mich jetzt, wo die Anweisung dafür herkommt. Von mir ist sie nicht, und ich verstehe auch nicht, wie es sein kann, dass das im Namen meiner `main()` geschieht. Ich habe gelesen, dass man das über eine Umgebungsvariable(?) `RAMEND` kontrollieren könne, aber ich weiß nicht wo, d.h. an welcher Stelle sie existieren muss. Vor `avr-gcc main.cpp ...` ändert das nichts. Ich bin noch recht neu in der Materie, würde den Sachverhalt gerne verstehen, und bin für jegliche Hilfe dankbar.
Markus R. schrieb: > Die weitere Untersuchung am Simulator > ergab, dass in der assemblierten `main()` der Stackpointer umgesetzt > wird. Während er Anfangs bei 0x08ff liegt, wird er auf signifikant > weniger herabgesetzt. > > Ich frage mich jetzt, wo die Anweisung dafür herkommt. Von mir ist sie > nicht, Tja, von jemandem muß sie aber sein. Irgend jemand wird da ein großes Array o.ä. auf dem Stack anlegen. Wenn nicht du, wer dann? Oliver
Markus R. schrieb: > und bin für jegliche Hilfe dankbar. Ohne deine Sourcen zu sehen wird das wohl schwierig werden.
Oliver S. schrieb: > Tja, von jemandem muß sie aber sein. Irgend jemand wird da ein großes > Array o.ä. auf dem Stack anlegen. Wenn nicht du, wer dann? Eine Rekursion?!?!
Wenn Du in C++ deine Objekte dynamisch anlegst, brauchst Du viel Platz im RAM, auch wenn du Klassen hast, die viel kopieren, also nen Kopierkonstruktor besitzen. Also, statt Medusa *Lotta = new Medusa(roter_rock,silberne_highheels); lieber Medusa.Lotta(roter_rock,silberne_highheels); verwenden. :-P mfg
Naja, es war gestern ein bissel spät, ich muß die Zeile Medusa.Lotta(roter_rock,silberne_highheels); berichtigen, da muß es natürlich heißen: Medusa Lotta(roter_rock,silberne_highheels); also ohne den Punkt. Wenn Du Klassen dynamisch zuweist, vergiß bitte nach Gebrauch der Klasse das rausschmeißen aus dem Speicher nicht, also Medusa *Lotta = new Medusa(roter_rock,silberne_highheels); Lotta -> Tanze("tanzvorlage.med"); ... // Nun ist Lotta fertig und möchte raus if(Lotta) { delete Lotta; Lotta = nullptr; // oder Lotta = NULL; } Jetzt erst räumt Lotta ihren Speicher, und Du kannst ihn neu verwenden. Dasselbe gilt auch für asm. Gehe deine Quellen pedantisch durch, ob auch alle dyn. Speicheranforderungen zurückgenommen werden! mfg
Markus R. schrieb: > Ich frage mich jetzt, wo die Anweisung dafür herkommt. Von mir ist sie > nicht Muß sie aber. Default geht der Stack immer bis RAMEND, siehe hier: https://www.nongnu.org/avr-libc/user-manual/malloc.html
Für Mixprogramme *.C, *.S ist es immer das beste, für das *.S erstmal ein *.C zu schreiben, was alle Parameter und Variablen enthält und es nach *.S zu compilieren. Dann kann man darin bequem den Assemblercode einfügen.
Markus R. schrieb: > Ich frage mich jetzt, wo die Anweisung dafür herkommt. Der avr-gcc führt ein Stückchen Assembler Code aus, bevor er die main() Funktion aufruft. Ich nehme an, dass du diesen Code meinst. Der Code wird vom avr-gcc generiert. Beim arm-gcc würde er als *.s Datei vorliegen. Du kannst dir das Assembler-Listing generieren lassen, dann siehst du ganz genau, was der Compiler aus deinem Programm gemacht hat. avr-objdump -h -S programm.elf Ich habe mal ein Beispiel angehängt. Beim Reset wird dort zur Adresse 00000074 gesprungen, dort ist der interessante Teil, und zwar bis zur Zeile > a6: 0e 94 86 00 call 0x10c ; 0x10c <main> wo die main Funktion aufgerufen wird. Du siehst, dass da einiges vorher passiert. Man kann da übrigens sogar C Funktionen noch vor main() aufrufen. Zum Beispiel so:
1 | void my_init() __attribute__ ((naked)) __attribute__ ((section (".init5"))); |
2 | |
3 | void my_init() { |
4 | ...
|
5 | }
|
6 | |
7 | int main() { |
8 | ...
|
9 | }
|
Aber Achtung, es gibt Einschränkungen, was man in solchen Funktionen tun darf. Das ist in der Doku der avr-libc beschrieben.
Lotta . schrieb: > Wenn Du Klassen dynamisch zuweist, vergiß > bitte nach Gebrauch der Klasse das rausschmeißen aus dem > Speicher nicht, also Selbst wenn du recht hast, hat es doch nichts mit dem Problem zu tun. Denn new lässt zwar den Heap sich füllen, aber nicht den Stack in den Heap wachsen. Also: Deine Aussage ist richtig, aber Thema verfehlt.
Stefan ⛄ F. schrieb: > Markus R. schrieb: >> Ich frage mich jetzt, wo die Anweisung dafür herkommt. > > Der avr-gcc führt ein Stückchen Assembler Code aus, bevor er die > main() Funktion aufruft. Ich nehme an, dass du diesen Code meinst. Was mit dem Problem des TO überhaupt nichts zutun hat. Der Stack beginnt beim AVR-GCC mit avrlibc am Ende des SRams. Immer. Auch bei Arduino. Was ja der TO auch bestätigt, denn der Stackpointer ist zu Beginn von main genau da, wo er hingehört. Was davor passiert, ist für das Problem uninteressant. Alles, was nach dem Start von Main passiert, ist Anwenderprogramm. Da legt entweder eine Arduino-Lib oder der TO selber Daten auf den Stack. Da der Sourcecode aber geheim ist, muß der TO halt selber rausfinden, was er da eigentlich tut. Oliver
Vielen Dank schonmal für die Antworten! Ich habe mir ein minimales Beispiel erstellt, bei dem die Sache mit dem Stackpointer ebenfalls auftaucht. Mittlerweile habe ich herausgefunden, warum der Speicherverbrauch bei meinem Projekt zu einem Problem führt -- es wird einfach zu viel alloziert. Das hat aber mit der Umsetzung des Stackpointers nichts zu tun. Was mir noch dazu einfällt, hängt mit meinem build Prozess zusammen, da ich ja wie oben gesagt das [Arduino-Makefile](https://github.com/sudar/Arduino-Makefile) ist da noch Müll dabei. `/usr/bin/avr-gcc -mmcu=atmega328p -Wl,--gc-sections -Os -flto -fuse-linker-plugin -o build-nano-atmega328old/BlinkInAVRC_.elf build-nano-atmega328old/main.S.o build-nano-atmega328old/libcore.a -lc -lm` Ich weiß nicht, was libcore macht. Die Quellen habe ich noch nicht gefunden. Auf welchem Weg dabei dann die `main()` manipuliert wird, ist mir deshalb immer noch schleierhaft. Weil ich mir aber insgesamt mehr Kontrolle wünsche, werde ich wohl alles in Assembler umsetzen.
EAF schrieb: > Lotta . schrieb: >> Wenn Du Klassen dynamisch zuweist, vergiß >> bitte nach Gebrauch der Klasse das rausschmeißen aus dem >> Speicher nicht, also > > Selbst wenn du recht hast, hat es doch nichts mit dem Problem zu tun. > Denn new lässt zwar den Heap sich füllen, aber nicht den Stack in den > Heap wachsen. > > Also: Deine Aussage ist richtig, aber Thema verfehlt. Entschuldige bitte, @EAF, ich wollte doch blos helfen, und keine Märchen erzählen. Kannst Du mir noch mal verzeihen? :-O mfg
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.