Warum wächst der Stapel nach unten?

31

Ich gehe davon aus, dass es eine Geschichte gibt, aber warum wächst der Stapel nach unten?

Es scheint mir, dass Pufferüberläufe viel schwerer auszunutzen wären, wenn der Stack nach oben wächst ...

Mehrdad
quelle
3
stackoverflow.com/questions/1677415/… merkt an, dass der Stack bis zu einem gewissen Grad in beide Richtungen wachsen kann.
JB King
6
Es gibt eine Frage wie diese: stackoverflow.com/questions/2035568/… . Faktisch gibt es hier eine viel bessere Frage und Antwort: stackoverflow.com/questions/664744/…
Karlson
Die verknüpfte Frage behandelt das Problem des Pufferüberlaufs nicht ganz.
Deadalnix
1
weil der Haufen nach oben wächst.
Tylerl
2
Befindet sich Speicherplatz 0 oben oder unten?

Antworten:

21

Ich glaube, es stammt aus den Anfängen des Computerbetriebs, als der Arbeitsspeicher sehr begrenzt war, und es war nicht ratsam, einen großen Teil des Arbeitsspeichers für die ausschließliche Verwendung durch den Stapel vorab zuzuweisen. Wenn Sie also Heap-Speicher ab Adresse Null und Stapelspeicher ab Ende des Speichers zuweisen, können sich Heap und Stapel denselben Speicherbereich teilen.

Wenn Sie etwas mehr Heap benötigen, können Sie vorsichtig mit der Stapelverwendung umgehen. Wenn Sie mehr Stack benötigen, können Sie versuchen, etwas Heap-Speicher freizugeben. Das Ergebnis waren natürlich meist spektakuläre Abstürze, da der Stapel gelegentlich den Haufen überschrieb und umgekehrt.

Damals gab es kein Interwebz, daher gab es kein Problem mit Pufferüberlauf-Ausnutzungen. (Zumindest in dem Maße, in dem das Interwebz existierte, befand sich alles in Hochsicherheitseinrichtungen des Verteidigungsministeriums der Vereinigten Staaten, so dass die Möglichkeit böswilliger Daten nicht sonderlich berücksichtigt werden musste.)

Danach galt es bei den meisten Architekturen, die Kompatibilität mit früheren Versionen derselben Architektur aufrechtzuerhalten. Aus diesem Grund sind die Upside-Down-Stacks heute noch bei uns.

Mike Nakis
quelle
8
Gehen Sie zurück in die Geschichte und es gab keinen Heap, auch heute haben viele 8- und 16-Bit-Mikrocontroller keinen Heap. Der Stack wuchs herab, sodass das Programm in einer Adresse mit niedrigem Speicher installiert werden konnte und der Stack der verbleibende Speicher war. Die Stapelinitialisierung kann vor dem Laden des Programms durchgeführt werden, wodurch die Programme vereinfacht werden.
mattnz
1
Die meisten kleinen Mikrocontroller haben einen Haufen, nur keinen Haufen, der wächst. Es ist schwer zu rechtfertigen, die dynamische Speicherzuweisung auf dem Heap zu verwenden, wenn Sie nur wenig Arbeitsspeicher (<1 KB) zur Verfügung haben. Normalerweise ändert sich nur die Größe des Speicherbereichs im Stapel.
Tehnyit
7

Der Programmspeicher ist traditionell eingerichtet als

code
constants
heap (growing up)
...
stack (growing down)

Haufen und Stapel können ausgetauscht werden

Pufferüberläufe können jedoch weiterhin ausgenutzt werden, wenn der Stapel in die andere Richtung geht

wobei die klassischen strcpyals Beispiel

foo(char* in){
char[100] buff;
strcpy(buff,in);
}

mit Stapelspeicher als

ret foo
arg in
buff array
ret strcpy
buf pointer
in

Dies würde bedeuten, dass beim Kopieren die Rücksprungadresse für strcpynach dem Puffer steht (anstelle der fooRücksprungadresse) und von allem, was sich in diesem befindet, überschrieben werden kannin

Ratschenfreak
quelle
4

Bei einigen Hardware-Systemen beginnt der Heap bei hohem Arbeitsspeicher und wächst nach unten, während der Stack bei niedrigem Arbeitsspeicher beginnt.

Dies geschieht unter anderem mit der PA-RISC-Hardware von HP: http://www.embeddedrelated.com/usenet/embedded/show/68749-1.php

Das ehrwürdige Multics-Betriebssystem lief auf Hardware, auf der (einer von möglicherweise mehreren) Stacks aufwuchs: siehe http://www.acsac.org/2002/papers/classic-multics.pdf , Ende von Abschnitt 2.3.2:

Drittens wuchsen die Stapel auf den Multics-Prozessoren eher in die positive als in die negative Richtung. Wenn Sie also tatsächlich einen Pufferüberlauf durchführen würden, würden Sie nicht verwendete Stapelrahmen und nicht Ihren eigenen Rückgabezeiger überschreiben, was die Ausnutzung erheblich erschwert.

Das ist eine ziemlich interessante Aussage. Wurden Pufferüberläufe nur aufgrund der "üblichen" Prozedur-Aufruf-Stapel-Rahmen-Anordnung zu einem so großen Problem? Wie viel von Multics Ruf als Totally Invulnerable war nur ein Zufall für das Hardware-Design?

Bruce Ediger
quelle
Nun, es hat Multics wahrscheinlich genauso wenig geholfen, einen oder mehrere ausführbare Stacks zu haben wie die intelligente Stapelrichtung. Bei vielen Programmen, die in PL / 1 geschrieben wurden, waren Zeichenfolgenüberläufe natürlich auch kein wirkliches Problem.
Greg A. Woods