Wie wird der Boden des Stapels bestimmt?

8
  

Ein Stapel ist ein zusammenhängender Block von   Speicher mit Daten. Ein Register   nannte die Stapelzeiger (SP) Punkte   an die Spitze des Stapels. Der Boden   des Stapels ist an einer festen Adresse.

Wie ist der Stapel unten vom Kernel fixiert?

    
Mask 30.03.2010, 01:41
quelle

4 Antworten

6

Ich tippte eine längere Antwort ein, aber es regte sich, also hier ist ein kürzerer ...

Wenn ein Prozess gestartet wird, benötigt er einen Stapel zum Speichern temporärer Werte (d. h. automatische Zuweisung) oder Stapelrahmen, wenn Funktionen aufgerufen werden. Der Speicher für diesen Stack muss irgendwo herkommen.

Also erstellt das OS eine Zuordnung im virtuellen Speicher für den Stapel und weist den Stapelzeiger der hohen Adresse dieses Blocks zu. In einem Predecement-Stack, bei dem der Stack-Pointer vor der Dereferenzierung dekrementiert wird, ist der anfängliche Stack-Pointer tatsächlich die Adresse nach der letzten Adresse im zugeordneten Space.

Wenn der Prozess versucht, etwas auf den Stapel zu legen, führt dies zu einem Zugriff auf diesen Speicherbereich, dem kein physischer RAM zugeordnet ist. Dies führt zu einem Seitenfehler, der dazu führt, dass das Betriebssystem die am wenigsten genutzte (oder nahe gelegene) RAM-Seite in das Auslagerungslaufwerk oder die Auslagerungsdatei eingibt und die physische RAM-Seite der Stackseite neu zuweist, auf die zugegriffen wird. Jetzt, da es physischen RAM gibt, kehrt das Betriebssystem zurück und der Prozess wird fortgesetzt, indem die gepushten Daten in den Stapelspeicher abgelegt werden.

Was passiert also, wenn du alles vom Stapel entfernst und dann versuchst, es wieder zu tun? Dieser letzte Popup, bei dem der Stapelzeiger seinen Anfangswert hat, führt zu einem Zugriff auf eine virtuelle Speicheradresse, die dem Stapel nicht zugeordnet ist. Dies verursacht einen Segmentierungsfehler, was bedeutet, dass der Prozess versucht hat, auf Speicher zuzugreifen, den er niemals zugewiesen hat. Das Betriebssystem antwortet, indem es den Prozess beendet und alles aufräumt, was es kann.

Warum nicht eine Seite über das Ende des Stapels hinaus zuordnen? weil das dazu führen würde, nicht initialisiertes RAM zu lesen, das alles enthält, was diese Seite des physischen RAM benutzt. Es gibt einfach keine Möglichkeit, ein korrekt funktionierendes Programm zu erzeugen (um nicht zu sagen, dass dies ein riesiges Sicherheitsrisiko ist), daher ist es immer noch das Beste, das Programm zu beenden.

    
Mike DeSimone 30.03.2010 02:14
quelle
1

Das wäre Teil der Implementierung des Stacks selbst. Wenn Sie beispielsweise einen Stapel in C implementieren, können Sie den Stapelzeiger und die aktuelle Anzahl der Elemente speichern. Oder der Stapelzeiger zusammen mit der Basis des Stapels, etwa wie folgt:

%Vor%

Wenn Sie von einem CPU-Stack sprechen (Rückgabeadressen usw.), können Sie den Stack-Underflow aufgrund der Tatsache erkennen, dass Sie abstürzen. Schlecht.

Als ein Beispiel, in früheren Tagen, als Prozessoren auf 64K Adressraum beschränkt waren, testeten CPUs typischerweise Speicher, bis sie das erste Byte gefunden hatten, das nicht das gleiche wie das gerade geschriebene Wort (im Hochfahrprozess) gelesen hatte. Das war das erste Byte jenseits des tatsächlichen physischen Speichers, also setzten sie SP auf eins darunter. Natürlich, einige (kleine Anzahl von) Maschinen hatten 64K physischen RAM, also setzen Sie SP einfach an den Anfang des Adressraums.

Heutzutage ist der Prozess in riesigen Speicherbereichen mit virtuellem Speicher und Multitasking-Betriebssystemen ein wenig komplizierter, aber es läuft immer noch auf (in den meisten Fällen) ab:

  • Adressraum ist für einen Prozess reserviert.
  • SP ist irgendwo in diesem Adressraum eingestellt.
  • Prozess läuft.

Zu diesem Zeitpunkt sind Sie vermutlich auf sich allein gestellt, was den Kernel betrifft. Die Verantwortung endet an dem Punkt, an dem der Code gestartet wird und nicht nur das Wechseln von Aufgaben und das Bereitstellen von Diensten wie gewünscht, aber das hat nichts mit Ihrem Stack zu tun. Wenn Ihr Buggy-Code den Stack über- oder unterläuft, ist das Ihr Problem.

Der Kernel darf Ihren SP auf Taskwechsel überprüfen, um zu sehen, ob Sie etwas falsch gemacht haben, aber das ist keineswegs garantiert. Es kann auch einen Hardware-Speicherschutz verwenden, um einen Unterlauf zu erkennen (wenn der Stapel an der Spitze des zugewiesenen Adressraums liegt). Aber das hängt wiederum ganz von dem Kernel ab, den Sie verwenden.

    
paxdiablo 30.03.2010 01:45
quelle
0

Ich nehme an, dass du meinst "im Speicher des Prozesses fixiert" und nicht "im Gesamtspeicher fixiert". Sie können in jedem Linux-System nachsehen, wo sich der Stapelboden befindet, indem Sie nach einer Zeile wie

suchen %Vor%

in der Ausgabe von cat /proc/<pid-here>/maps . Der untere Teil des Stacks ist in diesem Fall 0xbffeb000 . In meinem System scheinen alle Stack-Bottoms in einem von Bffca000 bffcb000 bffdd000 bffe0000 bffe4000 bffe6000 bffeb000 (nach dem Durchlaufen von ~ 200 Prozessen) zu fallen.

Ich vermute, dass diese Werte tief im Kernel zugewiesen werden, wo auch immer Prozesse erstellt werden.

    
tucuxi 30.03.2010 02:14
quelle
0

Tatsächlich gibt es etwas nach dem Ende des Stapels. Nach dem Stapel gibt es die Elemente des argv-Arrays und dann die Elemente des env-Arrays. Darauf folgt eine Barriere, dann libc code.

    
Joshua 05.10.2011 16:12
quelle

Tags und Links