Forum: Mikrocontroller und Digitale Elektronik Bezüglich Stack, Heap, Ram etc. auf µC


von Tob75 (Gast)


Lesenswert?

Hallo Experten,

ich habe ein paar grundsätzliche Fragen zum Programmieren eines µC. Ich 
selbst programmiere µC auf ARM Cortex-M4 Basis, falls das bei den Fragen 
eine Rolle spielt.

- Werden lokale Variablen werden sofort nach Start des µC in den SRAM 
gelegt? Liegen diese liegen im Stack?
- Globale Variablen werden auch sofort nach Start in den SRAM gelegt? 
Diese liegen glaube nicht im Stack, ist das richtig?
- Wo sind constant Variablen allokiert? Liegen diese im Flash?
- Gibt es Richtlinien zur Dimensionierung des Stacks? Wodurch merkt man 
wann er zu klein ist?

Vielen Dank für eure Antworten!!

von Peter II (Gast)


Lesenswert?

Tob75 schrieb:
> Vielen Dank für eure Antworten!!

alle Fragen habe nicht mit dem µC zu tun sondern mit der 
Programmiersprache und deren Einstellungen. Davon hast du uns aber keine 
Info geliefert.

von Tobias P. (hubertus)


Lesenswert?

Hallo,

> Gibt es Richtlinien zur Dimensionierung des Stacks? Wodurch merkt man
> wann er zu klein ist?

Theoretisch kannst du den Stack exakt bemessen. Zunächst mal: mach ihn 
so gross wie möglich. Dann fülle ihn mit einem bestimmten Bitmuster, 
z.B. 0xAFFEAFFE oder 0xDEADBEEF oder so etwas. Und dann lass einfach 
deine Software laufen. Später kannst du dann z.B. mit dem Debugger 
schauen, bis wie weit herunter dein Bitmuster überschrieben wurde, so 
eine Art 'Wassermarke' oder sowas in der Art. Das war der grösste 
Stackverbrauch. Einerseits könnte man den also so bemessen. Andererseits 
könntest du auf dem PC in deiner Entwicklungsumgebung z.B. mit Doxygen 
oder so einen Callgraph erzeugen lassen und die tiefste Verschachtelung 
von Funktionen bestimmen. Da jeder Funktionsaufruf einen bestimmten 
Stackverbrauch mit sich zieht, kann man dann so den Stackverbrauch 
abschätzen.

> Wo sind constant Variablen allokiert? Liegen diese im Flash?

ja.

> Globale Variablen werden auch sofort nach Start in den SRAM gelegt?
> Diese liegen glaube nicht im Stack, ist das richtig?

Nein, weil sie global sind. Die liegen 'irgendwo' im Memory. Je nach dem 
ob sie mit 0 initialisiert werden oder nicht liegen sie im BSS-Segment 
oder aber in einem anderen Segment, dessen Name mir jetzt nicht einfällt 
und das durch die Kopierereri im Startup-Code initialisiert wird. 
Genauso wie die lokalen static-Variablen in Funktionen. Die liegen im 
selben Segment. Aber 'normale' auto-Variablen liegen auf dem Stack.


Gruss
Tobias


Edit: Peter II war schneller. Er hat natürlich recht, aber ich gehe mal 
von C aus ;-)

: Bearbeitet durch User
von P. M. (o-o)


Lesenswert?

Tob75 schrieb:
> - Werden lokale Variablen werden sofort nach Start des µC in den SRAM
> gelegt? Liegen diese liegen im Stack?

Lokale Variablen liegen im Stack und werden dann angelegt, wenn sie im 
Programmcode deklariert werden.

> - Globale Variablen werden auch sofort nach Start in den SRAM gelegt?
> Diese liegen glaube nicht im Stack, ist das richtig?

Globale Variablen werden beim Start in den SRAM gelegt und zwar nicht in 
den Stack, sondern in einen separaten Bereich für globale Variablen. 
(Optimierungen und Eigenheiten des Compilers ausgenommen.)

> - Wo sind constant Variablen allokiert? Liegen diese im Flash?

Kann, muss aber nicht sein. Wenn der Mikrocontroller nicht unkompliziert 
direkt wahlfrei aus dem Flash lesen kann, so wird man sie eher im RAM 
anlegen.

> - Gibt es Richtlinien zur Dimensionierung des Stacks? Wodurch merkt man
> wann er zu klein ist?

Typischerweise wächst der Stack vom oberen Ende des Speichers nach 
unten, während alles andere von unten nach oben wächst. So kollidieren 
der Stack erst mit dem Rest des Speichers, wenn der Speicher randvoll 
ist. Das merkst du daran, dass dein Programm komplett verrückt spielt.

Den Stack "dimensioniert" man somit eigentlich nicht. Man muss bloss 
sicherstellen, dass er nie zu gross wird. Auf einem ARM dürfte das aber 
ohne Rekursion fast nicht passieren.

von Tob75 (Gast)


Lesenswert?

Danke für die schnellen antworten. Und um die Info nachzureichen: Ja ich 
programmiere nur in C und die Entwicklungsumgebung (Rowley Crossworks) 
verwendet den GCC.

von Karol B. (johnpatcher)


Lesenswert?

Tob75 schrieb:
> - Wo sind constant Variablen allokiert? Liegen diese im Flash?

Diese Frage hängt stark von der verwendeten Plattform und den 
verwendeten Werkzeugen ab. AVRs mit ihrer Harvard Architektur werden 
auch das im RAM ablegen. Hier bedarf es einiger Tricks (Attribute 
PROGMEM), um das Ganze wirklich in den Flash-Speicher zu bekommen.

"const" ist überhaupt nur ein Hinweis an den Compiler (und an 
Mitmenschen), dass der Inhalt der Variable nicht verändert wird. Dadurch 
kann der Compiler vor Dummheiten warnen und ggf. Optimierungen 
durchführen. In erster Linie kann man sich das aber wie "normale" 
Variablen vorstellen.

Mit freundlichen Grüßen,
Karol Babioch

von c-hater (Gast)


Lesenswert?

Tobias Plüss schrieb:

> Theoretisch kannst du den Stack exakt bemessen. Zunächst mal: mach ihn
> so gross wie möglich. Dann fülle ihn mit einem bestimmten Bitmuster,
> z.B. 0xAFFEAFFE oder 0xDEADBEEF oder so etwas. Und dann lass einfach
> deine Software laufen. Später kannst du dann z.B. mit dem Debugger
> schauen, bis wie weit herunter dein Bitmuster überschrieben wurde, so
> eine Art 'Wassermarke' oder sowas in der Art. Das war der grösste
> Stackverbrauch.

Gefährlicher Ansatz. Hierbei ist nicht sichergestellt, daß der worst 
case während der Prüfzeit überhaupt aufgetreten ist. Also besser ganz 
schnell wieder vergessen.

> Andererseits
> könntest du auf dem PC in deiner Entwicklungsumgebung z.B. mit Doxygen
> oder so einen Callgraph erzeugen lassen und die tiefste Verschachtelung
> von Funktionen bestimmen.

Schon besser, aber immer noch nur die halbe Miete. Der Stackverbrauch 
von Interrupts muß gesondert berücksichtigt werden.

von Klaus W. (mfgkw)


Lesenswert?

c-hater schrieb:
>> Andererseits
>> könntest du auf dem PC in deiner Entwicklungsumgebung z.B. mit Doxygen
>> oder so einen Callgraph erzeugen lassen und die tiefste Verschachtelung
>> von Funktionen bestimmen.
>
> Schon besser, aber immer noch nur die halbe Miete. Der Stackverbrauch
> von Interrupts muß gesondert berücksichtigt werden.

zzgl. Rekursion...

von Rolf M. (rmagnus)


Lesenswert?

c-hater schrieb:
>> Später kannst du dann z.B. mit dem Debugger schauen, bis wie weit
>> herunter dein Bitmuster überschrieben wurde, so eine Art 'Wassermarke'
>> oder sowas in der Art. Das war der grösste Stackverbrauch.
>
> Gefährlicher Ansatz. Hierbei ist nicht sichergestellt, daß der worst
> case während der Prüfzeit überhaupt aufgetreten ist.

Immer noch besser als die Art, wie es normalerweise ermittelt wird, 
nämlich gar nicht.

>> Andererseits könntest du auf dem PC in deiner Entwicklungsumgebung z.B.
>> mit Doxygen oder so einen Callgraph erzeugen lassen und die tiefste
>> Verschachtelung von Funktionen bestimmen.
>
> Schon besser, aber immer noch nur die halbe Miete. Der Stackverbrauch
> von Interrupts muß gesondert berücksichtigt werden.

Und den Aufwand gibst du dir für jedes Programm?

von (prx) A. K. (prx)


Lesenswert?

Mal von C und ähnlichen Sprachen ausgehend, üblicherweise:

Tob75 schrieb:
> - Werden lokale Variablen werden sofort nach Start des µC in den SRAM
> gelegt?

Nein. Der Platz wird meist am Anfang einer Funktion auf dem Stack 
angelegt und mit Beendigung wieder freigegeben. Drum ist es ein Stack.

Ausnahme: Lokale Variablen mit "static" dran. Die sind vom Speicher her 
wie globale Variablen, aber nur in der Funktion selbst per Name 
ansprechbar.

> Liegen diese liegen im Stack?

Ja. Ausnahme sind kleine µC wie z.B. 8051 und PIC16, die sich mit der 
Verwendung von Stacks als Speicher für Variablen etwas schwer tun, und 
deren Compiler deshalb auch lokale Variablen gerne statisch anlegen, 
ggf. überlappend.

> - Globale Variablen werden auch sofort nach Start in den SRAM gelegt?
> Diese liegen glaube nicht im Stack, ist das richtig?

Ja.

> - Wo sind constant Variablen allokiert? Liegen diese im Flash?

Keine generelle Regel. Aber als Daumenregel kann man wohl sagen, dass 
dies nur der Fall ist, wenn das Flash im Datenadressraum liegt. Bei 
32-Bittern ist das üblich, bei kleineren teils nicht.

> - Gibt es Richtlinien zur Dimensionierung des Stacks? Wodurch merkt man
> wann er zu klein ist?

Das er überläuft. :-)

Im Ernst: es gibt keine Regel dafür wie sich das äussert. In vielen 
Umgebungen laufen Stack und Heap / statische Daten gegeneinander, 
weshalb ein überbordender Stack zunächst in den Heap und dann in die 
statischen Daten reinläuft und da Chaos anrichtet. Aber es gibt auch 
andere Umgebungen.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Tob75 schrieb:
> - Wo sind constant Variablen allokiert? Liegen diese im Flash?

konstante auto-Variable liegen (immer?) auf dem Stack.

von (prx) A. K. (prx)


Lesenswert?

Steffen Rose schrieb:
> konstante auto-Variable liegen (immer?) auf dem Stack.

Oder nirgends. Oder werden statisch angelegt, weil sie als 
unveränderlich nicht reentrant sein müssen:
1
int g(const int *);
2
3
int f(void)
4
{
5
        const int x[2] = { 1, 2 };
6
        return g(x);
7
}
1
f:
2
        subl    $12, %esp
3
        movl    $x.1281, (%esp)
4
        call    g
5
        addl    $12, %esp
6
        ret
7
x.1281:
8
        .long   1
9
        .long   2

Lokale Variablen liegen je nach Prozessor auch in Registern, ohne dass 
auf dem Stack dafür Platz angelegt werden muss. Oder sie liegen 
nirgends, weil vollständig wegoptimiert.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Ja stimmt. Hatte nur die Postings im Kopf, dass diese häufig im Flash 
liegen und wollte dem widersprechen.

von Bernhard D. (pc1401)


Lesenswert?

Steffen Rose schrieb:
> Tob75 schrieb:
>> - Wo sind constant Variablen allokiert? Liegen diese im Flash?
>
> konstante auto-Variable liegen (immer?) auf dem Stack.

Konstante Variablen?

von Steffen R. (steffen_rose)


Lesenswert?

unveränderliche Variable (versteht so bloß keiner, was gemeint ist)

Edit: ok, auch nicht viel besser.

Ich wollte auf den Unterschied zwischen
Konstanten mit automatic storage
und static Konstanten aufmerksam machen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Bernhard D. schrieb:
> Konstante Variablen?

Stimmt schon. Leider. In C ist
   const int n = 10;
keine lexikalische Konstante, sondern tatsächlich eine unveränderliche 
Variable.

In C++ ist das etwas anders (und komplizierter :-).

von Falk B. (falk)


Lesenswert?

@ P. M. (o-o)

>Typischerweise wächst der Stack vom oberen Ende des Speichers nach
>unten, während alles andere von unten nach oben wächst. So kollidieren
>der Stack erst mit dem Rest des Speichers, wenn der Speicher randvoll
>ist. Das merkst du daran, dass dein Programm komplett verrückt spielt.

Naja, manchmal hat man aber auch Pech und es kommt zu Fehlern, die lange 
nicht auffallen, z.B. weil eine maximale Stacktiefe nur selten erreicht 
wird oder nur kleine Fehler passieren aber kein Absturz bzw. massives 
Fehlverhalten. Wäre das nicht ein wichtiges Feature für CPUs, eine 
Stackprüfung in HARDWARE? Oder wenigstens in Software? Und damit meine 
ich nicht den Trick mit dem Füllmuster, sondern eine automatische 
Prüfung des Stacks bei jedem Funktionsaufruf!

von Mark (Gast)


Lesenswert?

Falk Brunner schrieb:
> Wäre das nicht ein wichtiges Feature für CPUs, eine
> Stackprüfung in HARDWARE? Oder wenigstens in Software? Und damit meine
> ich nicht den Trick mit dem Füllmuster, sondern eine automatische
> Prüfung des Stacks bei jedem Funktionsaufruf!
Ja, das fände ich auch wichtig. Ein Stack-Underrun-Interrupt bzw. eine 
Exception sollte sich mit einem einfachen Compare realisieren lassen.

Gibt es Architekturen, die sowas schon unterstützen?

Wie sieht eine brauchbare Realisierung in Software aus?
Eine Abfrage bei jedem Funktionsaufruf dürfte zuviel Performance kosten.

Mark

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> Wäre das nicht ein wichtiges Feature für CPUs

Ausserhalb der kleinen µC-Sphäre lässt sich das oft mühelos über die 
Speicherverwaltung erledigen. Also indem der Stack sein Ende in einem 
finalen page fault findet. Der Compiler muss dann nur drauf achten, dass 
bei grossen lokalen Daten die guard page nicht übersprungen wird, muss 
also ggf. bei Arrays entsprechende Zugriffe alle paar KB einflechten.

> Oder wenigstens in Software?

Gibts in GCC im Prinzip, wobei es natürlich Sache der 
Zielsystemanpassung ist, etwas draus zu machen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

P. M. schrieb:
> Typischerweise wächst der Stack vom oberen Ende des Speichers nach
> unten

Bei den 16-Bittern von Microchip, also PIC24/30/33, wächst der Stack 
aufwärts. Irgendwas macht Microchip eben immer anders. ;-)

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Rolf Magnus schrieb:

> Und den Aufwand gibst du dir für jedes Programm?

Natürlich. Ich bin der Programmierer und deshalb nicht nur dafür 
verantwortlich, sondern auch dazu in der Lage.

Wer sonst sollte das denn deiner Meinung nach tun? Der Pförtner?

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.