Forum: Mikrocontroller und Digitale Elektronik Memory Segmente


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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. (stefanus)


Bewertung
0 lesenswert
nicht 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.

: Bearbeitet durch User
von georg (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

8051

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.