Forum: Mikrocontroller und Digitale Elektronik Memory Segmente


von Peter (Gast)


Lesenswert?

Hallo,

Bei einem Mikrocontroller gibt es ja, soweit mein rudimentäres Wissen, 
die Bereiche: text, bss, data, heap und stack.

Die Größe des Stack und des Heap kann man selber festlegen, innerhalb 
gewisser Rahmenbedingungen natürlich. Dies kann ich im Linker Script 
*.ld durchführen.

Sofern der Code aus dem Ram ausgeführt werden soll, können auch die 
anderen Segment in Startadresse und Länge frei konfiguriert werden?

Quasi:
.text  Segment beginnt an Adresse ... und hat die Länge ... .
.bss   Segment beginnt an Adresse ... und hat die Länge ... .
.data  Segment beginnt an Adresse ... und hat die Länge ... .
.heap  Segment beginnt an Adresse ... und hat die Länge ... .
.stack Segment beginnt an Adresse ... und hat die Länge ... .

Geht das und wo wird dieses "Setting" gemacht? Linker Script *.ld bei 
gnu Compiler / Linker? Die Frage gilt insbesondere für das .text 
Segment.

von user (Gast)


Lesenswert?

Ja kann man festlegen im linker script:

z.B. für 68000:

OUTPUT_ARCH(m68k)
MEMORY
{
  CHIPRAM (rwxa) : ORIGIN = 0x00000000, LENGTH = 0x00200000
  ROM     (r xa) : ORIGIN = 0x00F80000, LENGTH = 0x00080000
  FASTRAM (rwxa) : ORIGIN = 0x08200000, LENGTH = 0x04800000
}
SECTIONS
{
  chipram :
  {
    *(.chipram .chipram.*)
    *(.text .text.*)
    *(.data .data.*)
  } >CHIPRAM
  fastram :
  {
    *(.fastram .fastram.*)
  } >FASTRAM
  rom :
  {
    *(.rom .rom.*)
  } >ROM
}

von S. R. (svenska)


Lesenswert?

Peter schrieb:
> Bei einem Mikrocontroller gibt es ja, soweit mein rudimentäres Wissen,
> die Bereiche: text, bss, data, heap und stack.

Diese Segmente gelten für die Anwendung, nicht für den Mikrocontroller 
selbst. Der hat nur Adressbereiche, die irgendwie auf Flash, RAM etc. 
abgebildet sind.

Das Linkerscript gibt an, welche Segment der Anwendung in welchen 
Speicherbereich des Controllers gelegt werden soll.

von Stefan F. (Gast)


Lesenswert?

Normalerweise ergibt sich Größe der Segmente text, bss und data aus dem 
Quelltext. Eine manuelle Größenvorgabe erscheint mir wenig Sinnvoll.

heap und stack teilen sich üblicherweise den gesamten übrigen RAM, der 
nicht fest vergeben ist. Der Heap beginnt an der ersten freien RAM zelle 
und wächst nach oben, während der Stack am oberen Ende des RAM Beginnt 
und nach unten wächst (oder umgekehrt).

Bei heap und stack kann man Größenbeschränkungen einstellen, welche von 
der Toolchain beim Bauen des Programm grob* überprüft werden. Sie sind 
in der Regel aber keine harte Grenze, da wie gesagt der ganze freie RAM 
dynamisch für Heap und Stack aufgeteilt wird.

Bei PC's sieht das anders aus, da bekommst du normalerweise einen 
Programmabbruch, wenn das Programm mehr Stack oder Heap belegt, als es 
darf. Wobei meisten nur der Stack begrenzt ist.

*) Wobei ich die Prüfung für wenig hilfreich halte, denn die Toolchain 
weiß zu wenig vom Verhalten der Anwendung zur Laufzeit.

von georg (Gast)


Lesenswert?

Peter schrieb:
> .text  Segment beginnt an Adresse ... und hat die Länge ... .

Programm und Daten belegen soviel RAM wie sie eben belegen, es ist wenig 
sinnvoll zur Länge Angaben zu machen - gibt man zu wenig an, läuft das 
Programm nicht (bzw. wird garnicht erst gelinkt), gibt man zuviel an ist 
der Platz verschwendet. Zum Stack ist zu beachten, dass der immer von 
oben herab belegt wird, jedenfalls ist mir noch nie eine Architektur 
begegnet, bei der ein Push die Adresse nicht dekrementiert. Daher 
bewegen sich Heap und Stack i.A. aufeinander zu. Die mögliche Kollision 
kann man zwar überwachen, aber was soll ein Embedded Controller denn für 
eine Konsequenz ziehen ausser die Arbeit einzustellen bzw. neu zu 
starten?

Georg

von c-hater (Gast)


Lesenswert?

Peter schrieb:

> Bei einem Mikrocontroller gibt es ja, soweit mein rudimentäres Wissen,
> die Bereiche: text, bss, data, heap und stack.

Nö, der µC hat von solchen Bereichen keinerlei Ahnung. Diese Bereiche 
(es gibt noch ein paar mehr) sind mehr so Konventionen, nach denen die 
Ergebnisse von Kompilern halbwegs organisiert einsortiert werden, um 
dann letztlich auf den tatsächlich verfügbaren Speicher des µC verteilt 
zu werden.

> Sofern der Code aus dem Ram ausgeführt werden soll, können auch die
> anderen Segment in Startadresse und Länge frei konfiguriert werden?

Grundsätzlich ja.

> Geht das und wo wird dieses "Setting" gemacht? Linker Script *.ld bei
> gnu Compiler / Linker?

Genau, dafür ist der Linker zuständig. Wie der nun genau konfigieriert 
wird, hängt wiederum vom Linker ab. Und welche Konfiguration sinnvoll 
ist, hängt von der Funktion des Programms und dem Zielsystem ab.

von S. R. (svenska)


Lesenswert?

Stefanus F. schrieb:
> heap und stack teilen sich üblicherweise den gesamten übrigen RAM, der
> nicht fest vergeben ist. Der Heap beginnt an der ersten freien RAM zelle
> und wächst nach oben, während der Stack am oberen Ende des RAM Beginnt
> und nach unten wächst (oder umgekehrt).

Das kann man frei festlegen. Es gibt auch Controller mit mehreren 
unzusammenhängenden Speicherbänken (z.B. SAM3), da kann man dann Heap 
und Stack unterschiedlich verteilen. Ob das sinnvoll ist, hängt vom 
Programm ab...

> Bei heap und stack kann man Größenbeschränkungen einstellen, welche von
> der Toolchain beim Bauen des Programm grob* überprüft werden. Sie sind
> in der Regel aber keine harte Grenze, da wie gesagt der ganze freie RAM
> dynamisch für Heap und Stack aufgeteilt wird.

...aber auf diese Weise bekommt man bei Überschreitung der reservierten 
Speicherbereiche möglicherweise direkt eine Exception, oder man kann der 
MPU die Arbeit zumindest erleichtern, wenn man denn will.

Die "data-bss-heap-stack"-Reihenfolge ist nur Konvention. Es kann auch 
durchaus sinnvoll sein, einen Block fixer Größe für data und heap oben 
in den Adressraum zu legen und den Stack darunter beginnen zu lassen. 
Dann knallt ein Stack-Overflow immer und Heap-Overflows kann man in 
_brk() feststellen.

> Bei PC's sieht das anders aus, da bekommst du normalerweise einen
> Programmabbruch, wenn das Programm mehr Stack oder Heap belegt, als es
> darf. Wobei meisten nur der Stack begrenzt ist.

Sowohl Stack als auch Heap sind auf PCs durch das Betriebssystem 
vorgegeben, und beide sind (mit unterschiedlichen Grenzen) begrenzt. 
Allerdings bekommt man statt "Speicher ist alle" im Zweifelsfall eher 
ein SIGKILL, denn reale Anwendungen sind notorisch schlecht darin, mit 
fehlendem Speicher umzugehen.

Du kannst ja testweise mal das Overcommitment im Linux-Kernel 
abschalten. :-)

> *) Wobei ich die Prüfung für wenig hilfreich halte, denn die Toolchain
> weiß zu wenig vom Verhalten der Anwendung zur Laufzeit.

Dafür gibt es eine MPU und Guard-Pages (da die MPU nicht bytegenau ist). 
Die Prüfung erfolgt sinnvollerweise durch Hardware, aber die zu 
prüfenden Parameter kommen von der Anwendung.

Die Toolchain prüft nur, ob die Segmente auch in die zugewiesenen 
Speicher passen (d.h. text+rodata und data+bss, heap und stack werden 
nicht geprüft). Schlägt das fehl, läuft das Programm garantiert nicht.

von Rolf M. (rmagnus)


Lesenswert?

georg schrieb:
> Die mögliche Kollision
> kann man zwar überwachen, aber was soll ein Embedded Controller denn für
> eine Konsequenz ziehen ausser die Arbeit einzustellen bzw. neu zu
> starten?

Das wäre oft durchaus eine bessere Option, als einfach irgendwas 
unvorhergesehenes zu machen, weil Variablen sich gegenseitig 
überschreiben.

S. R. schrieb:
> Die "data-bss-heap-stack"-Reihenfolge ist nur Konvention. Es kann auch
> durchaus sinnvoll sein, einen Block fixer Größe für data und heap oben
> in den Adressraum zu legen und den Stack darunter beginnen zu lassen.
> Dann knallt ein Stack-Overflow immer und Heap-Overflows kann man in
> _brk() feststellen.

Die klassische Reihenfolge hat allerdings den Vorteil, dass man den 
verfügbaren RAM am besten nutzt. Bei fixer Größe für Heap und Stack 
bleibt immer ein gewisser Verschnitt, und der Stack kann z.B. 
überlaufen, obwohl noch ein Haufen RAM frei ist.

von Falk B. (falk)


Lesenswert?

@Stefanus F. (stefanus)

>*) Wobei ich die Prüfung für wenig hilfreich halte, denn die Toolchain
>weiß zu wenig vom Verhalten der Anwendung zur Laufzeit.

Kommt drauf an. Wenn man keine dynamische Speicherverwaltung hat, ist 
der Speicherbedarf des Stacks eindeutig definiert, denn man hat nur 
konstante, globale Variabeln und lokale Variablen auf dem Stack. Die 
Reihenfolge der Funktionsaufrufe ist auch aus dem Quelltext 
analysierbar, selbst mit Interrupt.

Einzig bei rekursiven Funktionen wird es nicht vorhersagbar, denn sooo 
schlau ist der Compiler eher nicht, daß er die Programmlogik analysieren 
und die maximale Rekursionstiefe allein berechnen kann.

von c-hater (Gast)


Lesenswert?

Falk B. schrieb:

> Kommt drauf an. Wenn man keine dynamische Speicherverwaltung hat, ist
> der Speicherbedarf des Stacks eindeutig definiert

Unsinn. Offensichtliche Gegenanzeigen (für jeden echten Programmierer 
sofort als solche erkennbar):

- rekursive Algorithmen jeglicher Art
- zur Laufzeit festgelegte Funktionen (sprich: die Verwendung von
  Funktionszeigern)

> Einzig bei rekursiven Funktionen wird es nicht vorhersagbar, denn sooo
> schlau ist der Compiler eher nicht, daß er die Programmlogik analysieren
> und die maximale Rekursionstiefe allein berechnen kann.

Naja, immerhin. Einen offensichtlichen Knackpunkt dann doch noch selber 
gefunden. Aber nicht erkannt:

1) Ein Knackpunkt reicht als Gegenargument bereits völlig aus!

2) mit Funktionszeigern kann man immer auch Rekursionen erzeugen, von 
denen der Kompiler nicht einmal die Chance hat, den Rekursioncharakter 
zu erkennen, geschweige denn die maximale Tiefe der Rekursion...

Also ist es, wie Stefanus F. (sinngemäß) völlig korrekt gesagt hat: im 
Prinzip alles huppse...

von John Trafolta (Gast)


Lesenswert?

georg schrieb:
> edenfalls ist mir noch nie eine Architektur begegnet, bei der ein Push
> die Adresse nicht dekrementiert.

8051

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.