Forum: Mikrocontroller und Digitale Elektronik [AVR] Stack-Overflow: Was passiert dann genau?


von Wasserlaeufer (Gast)


Lesenswert?

Hallo !

Ich habe begriffen, was ein Stack-Overflow ist, aber was passiert dann 
mit dem Stack-Pointer? Läuft er wieder von oben ins SRAM? Oder bewegt er 
sich durch den I/O-Bereich, das heißt, schreibt er dann bei "call" oder 
"push" Daten in diese Register? Oder läuft er durch die "normalen" 32 
Register?

Im Datenblatt finde ich nichts dazu. :-(

von Schlammspringer (Gast)


Lesenswert?

Wasserlaeufer schrieb:
> Im Datenblatt finde ich nichts dazu. :-(

Und was dein Simulator, wenn du fleißig Bytes vom Stack holst?

von Roland (Gast)


Lesenswert?

Wenn die CPU einen Hardware-Stack hat, dürfte ein Reset kommen, wenn der 
Stackpointer aus den zulässigen Adressen rauskommt. Genaues sagt das 
DaBLa des betreffenden Kerns.

Beim Software-Stack (Stack im RAM) bekommt die CPU von allein nicht mit, 
dass der Stack überläuft. Die Adesse wird also beim push einfach 
weitergesetzt, und die CPU versucht die Adressen zu beschreiben. Beim 
pop analog wird normal ausgelesen und der Stackpointer zurückgezählt.

Solange der Pointer nicht eine Adresse erreicht, die beim Schreiben 
einen NMI auslöst, passiert (ausser sehr seltsamen Programmfehlern) nix 
weiter...

Besonders eklig wirds, wenn der Stack-Pointer Bereiche erreicht, in 
denen die Variablen stehen. Die werden dann nämlich überschrieben...

von H.Joachim S. (crazyhorse)


Angehängte Dateien:

Lesenswert?

siehe Bild - Frage beantwortet.
Dein Programm wird aber i.a. eher abstürzen, ehe der SP in den 
I/O-Bereich kommt :-)

von Roland (Gast)


Lesenswert?

PS: Welche Adressen/Register beim Überlauf überschrieben werden, siehst 
du an der Memory-map im DaBla deines Prozessors, und dem Wissen, wo du 
den Stack im RAM anlegst...

von Wasserlaeufer (Gast)


Lesenswert?

Danke euch für die vielen nützlichen Hinweise!

Verwendet habe ich einen ATmega328 mit Assembler.
Abgestürzt ist bis jetzt nichts. Das hat mich verwirrt....
Deswegen war ich mir nicht sicher, ob bei einem Push wirklich in 
Register geschrieben wird.

von Wasserlaeufer (Gast)


Lesenswert?

Wasserlaeufer schrieb:
> Abgestürzt ist bis jetzt nichts. Das hat mich verwirrt....
> Deswegen war ich mir nicht sicher, ob bei einem Push wirklich in
> Register geschrieben wird.

Nach weiteren Experimenten:

Weder push noch call oder rcall schreiben in Speicherbereiche, die 
außerhalb des SRAM liegen. Ich habe bis jetzt nirgends eine 
Dokumentation für dieses Verhalten finden können.

In meinem Fall ist es praktisch, dass beim Stacküberlauf nichts 
passieren kann. :-)  Andere wird es vielleicht enttäuschen, weil dadurch 
keine Register hilfsweise als Stack verwendet werden können.

Weitere Infos oder Doku jederzeit willkommen!

von Hmm (Gast)


Lesenswert?

Ich würde Deine Ergebnisse, wohl aber nicht Dein Bemühen, eher mit einer 
gewissen Skepsis sehen.
Zumindest bedürfen sie meiner Ansicht nach der weiteren Erläuterung.

Soweit ich weiss sind z.B. die Register, sowohl die Arbeitsregister als 
auch die Register der Peripherieeinheiten durchaus auch auf 
Speicherbereichen erreichbar; wenn auch je nach Atmel-Typ in 
verschiedenem Umfang und an anderen Adressen.

Deine Äusserung:

>Nach weiteren Experimenten:

>Weder push noch call oder rcall schreiben in Speicherbereiche, die
>außerhalb des SRAM liegen. Ich habe bis jetzt nirgends eine
>Dokumentation für dieses Verhalten finden können.

widerspricht dem nicht. Andererseits wäre es wissenswert ob Register 
verändert werden.

Auch ist mir an dieser Erklärung nicht klar, ob Du "Experimente" 
tatsächlich an der realen CPU durchgeführt hast und auf welche Weise.

Das in der Dokumentation pathologische Fälle eher selten wenn überhaupt 
geschildert werden überrascht mich nicht. Auch bei anderen Herstellern 
geschieht dies eher dann wenn tatsächlich eine Beschädigung auftreten 
könnte. Ein Fehlen der Beschreibung dieses Falles überzeugt mich nicht.

Warum ich so lange rede. Ich bin überzeugt davon das die Zugriffe via 
Stackpointer bei den AVRs mit Stack im RAM nicht überprüft werden und 
das jeder Zugriff tatsächlich ausgeführt wird egal ob da nun RAM oder 
ein memory-mapped Register dahinter liegt oder eben das "Nichts".

von Wasserlaeufer (Gast)


Lesenswert?

Hallo Hmm!

Hmm schrieb:
> Soweit ich weiss sind z.B. die Register, sowohl die Arbeitsregister als
> auch die Register der Peripherieeinheiten durchaus auch auf
> Speicherbereichen erreichbar; wenn auch je nach Atmel-Typ in
> verschiedenem Umfang und an anderen Adressen.

Richtig! Deswegen dachte ich ursprünglich mal, ein überlaufender Stack 
würde für Chaos sorgen.

> Deine Äusserung: (...)
> widerspricht dem nicht. Andererseits wäre es wissenswert ob Register
> verändert werden.

Sie wurden nicht verändert.

> Auch ist mir an dieser Erklärung nicht klar, ob Du "Experimente"
> tatsächlich an der realen CPU durchgeführt hast und auf welche Weise.

An einem echten ATmega328. Dessen SRAM beginnt bei 0x0100. Der 
Stackpointer läuft locker nach unten raus, also 0x00ff, 0x00fe usw., 
aber es wird in Adressen unter 0x100 per push nichts geschrieben. Ich 
habe das mit IO-Registern probiert und auch mit GP-Registern (r0 bis 
r31).

> Warum ich so lange rede. Ich bin überzeugt davon das die Zugriffe via
> Stackpointer bei den AVRs mit Stack im RAM nicht überprüft werden und
> das jeder Zugriff tatsächlich ausgeführt wird egal ob da nun RAM oder
> ein memory-mapped Register dahinter liegt oder eben das "Nichts".

Ja, diese Vermutung ist naheliegend, aber anscheinend ist es in der 
Praxis anders. So wie es aussieht, kann zwar z.B. sts in den gesamten 
Adressbereich schreiben, nicht aber push, call, rcall, also anscheinend 
alles was mit indirekter Adressierung über SP zu tun hat.

von Hmm (Gast)


Lesenswert?

Tut mir leid wenn ich nachbohre. Du glaubst nicht was man hier so an 
Textverständnis erlebt:

>> Auch ist mir an dieser Erklärung nicht klar, ob Du "Experimente"
>> tatsächlich an der realen CPU durchgeführt hast und auf welche Weise.

>An einem echten ATmega328.

Was heisst "echt"? Ich habe gefragt "real"! Im Simulator? Oder physisch 
vorhanden?

von Wasserlaeufer (Gast)


Lesenswert?

Hmm schrieb:
> Tut mir leid wenn ich nachbohre. Du glaubst nicht was man hier so an
> Textverständnis erlebt:

Voll ok. :-)
Ich lese hier auch oft mit und erlebe immer wieder, dass Leute 
aneinander vorbeireden.

>>An einem echten ATmega328.
>
> Was heisst "echt"? Ich habe gefragt "real"! Im Simulator? Oder physisch
> vorhanden?

Mit "echt" meinte ich "physisch". Versuchsaufbau: ATmega328-PU auf 
Breadboard, Angeschlossen über USBasp, der fürs Programmieren da ist und 
danach auch für die Stromversorgung sorgt. Als weitere Bauteile hatte 
ich nur eine Leuchtdiode und einen Vorwiderstand.

Jetzt kommt wahrscheinlich die berechtigte Frage, woher ich dann weiß, 
was nach den jeweiligen Versuchen in den Registern steht: ich habs 
einfach über die LED rausgemorst. Das mache ich öfter so, bin nämlich zu 
faul, viele Bauteile aufzustecken. :-)

von Hmm (Gast)


Lesenswert?

Interessant, wenn mir auch gerade keine nützliche Anwendung dafür 
einfällt. Hast Du das mal bei AVRFreaks gepostet?

von Wasserlaeufer (Gast)


Lesenswert?

Hmm schrieb:
> Interessant, wenn mir auch gerade keine nützliche Anwendung dafür
> einfällt. Hast Du das mal bei AVRFreaks gepostet?

Nein, bei denen war ich noch nie.
Wozu man das braucht? Auch eine gute Frage... Wenn man Interrupts nutzt, 
aber keinen Rücksprung braucht oder kein SRAM nutzen will, weil man es 
für andere Zwecke verwendet. Alles in allem irgendwelche seltenen 
Spezialfälle.

von H.Joachim S. (crazyhorse)


Lesenswert?

Werde ich morgen mal ausprobieren.
Definitiv war es früher so, dass der SP bei gewissenloser Nutzung alles 
platt gemacht hat :-)
Einen Unterschied sieht man aber schon im Datenblatt: die neueren Typen 
(wie 48/88/168/328) haben SP-init-Werte nach reset ramend. Die früheren 
Typen (z.B. Mega32) haben 0 im SP stehen. Offensichtlich hat Atmel die 
SP-Logik zumindest angefasst. Vielleicht auch einen (minimalen) 
Speicherschutz??
Aber einen wirklichen Nutzen hat es in der Tat nicht, zumindest sehe ich 
keinen.

von Wasserlaeufer (Gast)


Lesenswert?

H.joachim Seifert schrieb:
> Werde ich morgen mal ausprobieren.

Bin gespannt!

> Definitiv war es früher so, dass der SP bei gewissenloser Nutzung alles
> platt gemacht hat :-)

Meinst du mit "alles" das komplette SRAM oder auch alle anderen 
Register? Das SRAM wird immer noch überschrieben, daran hat sich nichts 
geändert.

Wenn du also ein Programm hast, das das SRAM verwendet, um dort 
Variablen abzulegen (wie z.B. bei C üblich), musst du aufpassen.

> Typen (z.B. Mega32) haben 0 im SP stehen. Offensichtlich hat Atmel die
> SP-Logik zumindest angefasst. Vielleicht auch einen (minimalen)
> Speicherschutz??

Ich hab den Verdacht, die früher fehlende automatische Initialisierung 
hat damit nichts zu tun.

von Hmm (Gast)


Lesenswert?

>Ich hab den Verdacht, die früher fehlende automatische Initialisierung
hat damit nichts zu tun.

Ich denke das hat er damit auch nicht sagen wollen.

Aber diese Aussage

>Meinst du mit "alles" das komplette SRAM oder auch alle anderen
>Register? Das SRAM wird immer noch überschrieben, daran hat sich nichts
>geändert.

>Wenn du also ein Programm hast, das das SRAM verwendet, um dort
>Variablen abzulegen (wie z.B. bei C üblich), musst du aufpassen.

weckt leider doch wieder meine Skepsis. Denn die Register sind (wie oben 
geschrieben in je nach Typ unterschiedlicher Weise und Umfang) auch in 
den Speicher abgebildet. Du kannst z.B. R1 bis R31 durch schreiben ins 
RAM ändern.

Zumindest solte noch ein Zweiter mal Deine Tests nachvollziehen.

Magst Du mal Deinen Testcode posten?

von H.Joachim S. (crazyhorse)


Lesenswert?

test:
#asm
   ldi r16, 0
   out SPH, r16
   ldi r16, 0xff
   out SPL, r16
   ldi r16, 0xaa
loop:
   push r16
   rjmp loop
#endasm

Mal kurz einen Mega16 auf das STK500 gesteckt und mit JTAG MKII und 
AVR-Studio laufen lassen (ich hoffe, das JTAG wirklich ein exaktes 
Prozessorbild liefert??) - der SP überschreibt weder I/O noch Register. 
Zählt aber brav bis 0 runter. Danach springt er übrigens auf 0x0fff...

Jetzt bin ich etwas ratlos.

von Hmm (Gast)


Lesenswert?

>(ich hoffe, das JTAG wirklich ein exaktes Prozessorbild liefert??)

Ich gehe davon aus, aber...

>Jetzt bin ich etwas ratlos.

...ich erwäge gerade meinen Glauben an den Weihnachtsmann wieder zu 
beleben. :-)

Witzig! Haben die Ings. bei Atmel das tatsächlich abgefangen.

von Blahblubber (Gast)


Lesenswert?

Es wäre auch mal interessant, was herauskommt, wenn man bei einem SP, 
der in die Register zeigt, einen Wert poppt. Der Wert des Registers, 0 
oder gar ff?

von H.Joachim S. (crazyhorse)


Lesenswert?

pop mit SP <0x60 liefert 0x00, zumindest laut JTAG.

von Wasserlaeufer (Gast)


Lesenswert?

H.joachim Seifert schrieb:
> Zählt aber brav bis 0 runter. Danach springt er übrigens auf 0x0fff...

Ah, interessant! Aber irgendwie logisch, denn der SP besitzt 
wahrscheinlich einen eigenen Hardware-Inkrementierer/Dekrementierer, da 
hat man sich ein paar Transistoren gespart, weil die High-Bits sowieso 
nicht verwendet werden. Irgendwo im Datenblatt steht sogar, dass die 
unbenutzten Bits des SP "don't care" sind, man sich deswegen auf deren 
Inhalt nicht verlassen darf und gut daran tut, sie auszumaskieren. 
Zumindest dieses Mysterium ist gelöst. ;-)

Ob der AVR-Simulator das alles auch berücksichtigt? Ich hab leider 
keinen.

von Klaus 2. (klaus2m5)


Lesenswert?

H.joachim Seifert schrieb:
> pop mit SP <0x60 liefert 0x00, zumindest laut JTAG.

Wenn das auch für RET/RETI gilt, landet das Programm sowieso irgendwann 
im Reset Vector.

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.