Premiere ! Meine erste Frage hier. Folgendes Problem: Ich definiere einen lokalen Puffer in main() #define BUFFER_SIZE 8192 int main(void) { unsigned char buffer[BUFFER_SIZE]; ..... Das Programm schmiert ab. Sieht nach Stack Überlauf aus. Je nachdem wie groß BUFFER_SIZE definiert wird stürzt es an unterschiedlichen Stellen ab. Mit BUFFER_SIZE 512 läuft es ohne Probleme. Wird buffer[] global definiert läuft alles einwandfrei ! #define BUFFER_SIZE 8192 unsigned char buffer[BUFFER_SIZE]; int main(void) { ..... Der LPC2136 hat 32kB RAM, und mein Programm braucht nicht mal 1,3kB davon. Abgesehen vom großen buffer[]. Zusammen also sagen wir mal 10kB. Mit lokalem buffer[] bekomme ich folgende Speicherbelegung: .text 18508 0 .data 4 1073741824 .bss 1316 1073741828 .stack 1024 1073743360 Mit globalem buffer[] sieht das so aus: .text 18440 0 .data 4 1073741824 .bss 9508 1073741828 .stack 1024 1073751552 Werden lokale Puffer auf dem Stack angelegt ? Das würde die Abstürze erklären.
Hi Holger, sofern du nicht static davor schreibst, liegt die Variable i.allg. auf dem Stack (machen zumindest C Compiler so). Mit static kann sie dort eigentlich nicht mehr liegen, weil der Wert der Variablen zwischen Aufrufen erhalten bleibt (d.h. diese Variable kann nur durch diese Funktion verändert werden).
P.S.: auf den Heap kannst du in C nur mit Hilfe der Funktionen für die dynamische Speicherverwaltung zugreifen. Das Stackgeschiebe rechnet der Compiler beim Übersetzen der Funktion aus. Wieviel Stack jedoch verfügbar ist, wird normalerweise erst zur Laufzeit festgelegt. Im allgemeinen ist zum Übersetzungszeitpunkt noch nicht klar, wie die Laufzeitumgebungen einer Funktion dimensioniert sind.
Hallo Micha, mit static funktioniert es jetzt auch lokal. Und der reale Speicherbedarf wird auch angezeigt. .text 18440 0 .data 4 1073741824 .bss 9508 1073741828 .stack 1024 1073751552 DANKE !
Hallo, ich hatte vor kurzen das gleiche Problem. Aber ich versteh immer nocht nicht, wie das sein kann. Wenn der Stack nach unten wächst, dann belegt er imer mehr Platz des Heaps, bis dieser ausgeht. Erst dann kommt es zu einer Kollosion zwischen dem Stack und den statischen Variablen. Wenn der LPC2136 32kb RAM hat und wie oben 1316 Bytes für statische Variablen braucht und 1024 Bytes für den Stack berechnet wurden, denn bleibt ja theoretisch 32768-1316-1024=30428 Bytes übrich für den Heap. Wie kann es dann sein, dass der Stack in .bss reinwächst? MfG Mark
WinARM selbst definiert kein Speicherlayout, das bleibt dem Anwender mit seinem individuellen Startup-Code und Linker-Script überlassen. Da holger darüber nicht informiert hat, kann hier nur spekuliert werden.
Hier ist mein komplettes Projekt. Der Stack ist fix auf 1024 Bytes definiert. Ich hab noch nicht rausgefunden wo. Viel Spaß beim suchen ;)
Wenn Du Dein Array innerhalb der Funktion deklarierst, ist es eine sogenannte "automatische Variable". Und die landen nicht auf dem Heap, sondern auf dem Stack. Einen Heap gibt es erst, wenn dynamische Speicherverwaltung mit malloc/new durchgeführt wird. Dein Stack ist 1 kByte groß, Deine Variable aber ist 8 kByte groß. Variablen, die außerhalb einer Funktion deklariert werden, sind keine automatischen Variablen und landen daher nicht auf dem Stack. Ebenso statische Variablen, die innerhalb einer Funktion deklariert werden.
Beim Stack hat man die Wahl wohin man ihn legt. - Eine gängige Version ist die von Mark skizzierte - am oberen Ende des Speichers anfangend abwärts gegen den Heap laufend. Vorteil: Sowohl Heap wie auch (System/User-) Stack können den gesamten Speicher nutzen, ohne vorher Limits festlegen zu müssen. - Die andere Variante legt ihn ans Ende des definierten Datenbereichs, und den Heap dahinter. Das ist die hier verwendete. Damit ist die Grösse aller Stacks zusammen entsprechend begrenzt. Entschieden wird das im Zusammenspiel von Linker-Script und Startup-Code.
Hallo Andreas, vielen Dank für die Erklärung. Jetzt verstehe ich auch das Problem, denn ich wusste nicht, dass es so etwas wie die zweite von Dir geschilderte Variante gibt. Wie kann man denn im Linkerscript einstellen, dass der Stack ganz am Ende platziert werden muss? MfG Mark
> Wie kann man denn im Linkerscript einstellen, dass der > Stack ganz am Ende platziert werden muss? Der Stack wird im Startup-Code geladen. Entscheidend ist womit. In hier gezeigten Fall wird das Symbol "_stack" dazu verwendet, das im Linker-Script am Ende der .stack Section plaziert wird. Alternativ kann man im Linker-Script die .stack Section auch ganz weglassen, und das entsprechende Symbol statt dessen direkt ans Ende vom RAM nageln: _stack = 0x40008000; Wobei man das im Startup-Code auch direkt so machen kann. Ich persönlich neige jedoch dazu, den Startup-Code innerhalb der LPC2000-Reihe gleich zu halten und die Abhängigkeiten vom jeweiligen Modell in Linker-Scripte zu verlagern. Wobei ich das Linker-Script aufteile: LPC2119.ld LPC2129.ld LPC2106.ld ... definert die MEMORY Areas und eben des Anfang der Stacks (5-zeiler). ROM.ld RAM.ld definiert basierend darauf die Sections (ROM-basiert und RAM-basiert) und ist modellunabhängig. Im Makefile stehen dann einfach beide Scripte nacheinander drin.
Auch wenn der Stack ganz am Ende anfängt, kann allzu bedenkenloser Umgang mit Stack Ärger verursachen: nämlich dann, wenn mehrere Tasks laufen und es keine Stacküberwachung gibt (häufig). Bei Erzeugen der Task muss normalerweise die Grösse des Stacks angegeben werden, mit dem die Task auskommen muss. Der Stack der nächsten Task fängt dann mittelbar (z.B. wg.TCB) oder unmittelbar danach an. Die Task die über ihren Stack hinausschreibt arbeitet dann zwar noch korrekt, aber sobald die Task, deren Stack sich anschliesst und der überschrieben wurde, den Prozessor zugeteilt bekommt, kommt's zu unvorhersehbarem Verhalten bzw. Abstürzen.
@Andreas kannst du mal so eine Linkerfile hier reinstellen. mgiaco
danke. muss es mal mit dem was ich habe vergleichen.
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.