Unter Windows wächst der Stapel von großen zu kleineren Adressen. Manchmal ist es architektonisch festgelegt, und manchmal ist es nur eine akzeptierte Vereinbarung. Der Wert des Stapelzeigers (Prozessorregister) ist ein Zeiger auf den Wert oben im Stapel. Werte, die sich tiefer im Stapel befinden, befinden sich jeweils an großen Adressen. Aber was passiert mit Daten, die sich an Adressen befinden, die kleiner als der Stapelzeiger sind?

Konventionen für einige (aber nicht alle) Architekturen definieren die rote Zone, die der Speicherbereich unter dem Stapelzeiger ist, aber für die Verwendung durch die Anwendung weiterhin gültig ist.

Unter Windows variiert die Größe der roten Zone je nach Hardwarearchitektur und ist häufig Null.
Architektur | Rote Zonengröße |
---|
x86 | 0 Bytes |
x64 | 0 Bytes |
Itanium | 16 Bytes * |
Alpha AXP | 0 Bytes |
MIPS32 | 0 Bytes |
Powerpc | 232 Bytes ** |
ARM32 | 8 Bytes |
ARM64 | 16 Bytes |
* Die Itanium-Plattform ist eine Besonderheit wert: Dort befindet sich die rote Zone über dem Stapelzeiger und nicht darunter.
** Bei PowerPC ist die rote Zone ein Nebeneffekt der Anrufvereinbarung .
Jeder Speicher hinter der roten Zone (unten im Stapel) wird als flüchtig angesehen und kann vom Betriebssystem jederzeit geändert werden.
Aber im Ernst, warum kümmert es das Betriebssystem, was ich mit meinem Stack mache? Ich meine, das ist mein Stapel! Das Betriebssystem sagt mir nicht, was ich mit dem Speicher tun soll, den ich über VirtualAlloc
. Was unterscheidet den Stack von anderen Speichern?
Betrachten Sie den folgenden Code für die x86-Plattform :
MOV [esp-4], eax ; eax MOV ecx, [esp-4] ; ecx CMP ecx, eax ; ? JNZ panic ; N: -
Erläuterung des Kommentars zur JNZ-AnweisungDie Assembly-Codierungskonvention besagt, dass Kommentare für Verzweigungsanweisungen das Ergebnis beschreiben sollten, wenn die Verzweigung abgeschlossen ist. Im obigen Beispiel stellt die CMP-Anweisung die Frage "Sind sie gleich?". Und der JNZ-Befehl springt, wenn sie nicht gleich sind. Daher beginnt der Kommentar mit „N:“, was bedeutet, dass der Übergang abgeschlossen ist, wenn die Antwort auf die vorherige Frage „Nein“ lautet, und der Rest des Kommentars beschreibt die Situation, in der der Übergang durchgeführt wird.
Assembler-Codierungskonvention?Ja, wir haben eine Codierungskonvention für Assembler.
Ist es möglich, dass ein bedingter Übergang implementiert wird?
Da es auf x86 keine rote Zone gibt, kann Speicher mit negativen Offsets relativ zum Stapelzeiger jederzeit überschrieben werden. Daher ist für den obigen Code der Übergang zum panic
möglich.
Der Debugger kann den Speicher hinter der roten Zone als geeigneten Ort zum Speichern seiner Daten verwenden. Wenn Sie beispielsweise den Befehl .call verwenden , führt der Debugger einen verschachtelten Aufruf auf demselben Stapel durch und verwendet wahrscheinlich einen Teil dieses Stapelspeichers, um die Register zu speichern, damit sie nach der Rückkehr von der aufgerufenen Funktion wiederhergestellt werden können. Daher werden alle außerhalb der roten Zone gespeicherten Daten zerstört.
Selbst während des normalen Betriebs kann das Betriebssystem jederzeit Daten außerhalb der roten Zone überschreiben. Hier zum Beispiel, wie dies passieren kann:
Angenommen, Ihr Thread führt sein Zeitfenster direkt nach dem Speichern der Daten hinter der roten Zone aus. Während Ihr Thread darauf wartet, die Ausführung fortzusetzen, nimmt der Speichermanager vorübergehend eine physische Seite aus Ihrem Code heraus. Am Ende erhält Ihr Thread wieder die Kontrolle und der Speichermanager versucht, die Codepage zurück zu tauschen (Seite in). Oh nein, beim Paging tritt ein E / A-Fehler auf! Das Betriebssystem STATUS_IN_PAGE_ERROR
den Ausnahmerahmen für STATUS_IN_PAGE_ERROR
auf den Stapel, was zu einer Datenbeschädigung führt, die Sie hinter der roten Zone gespeichert haben.
Das Betriebssystem löst diese Ausnahme aus. Es greift auf den Vector Exception Handler ( VEH ) zu, der ein weiterer Teil Ihres Programms ist. Der Handler wurde speziell für Ausnahmesituationen installiert, die sich aus dem möglichen Start Ihres Programms direkt von einer CD-ROM oder einem unzuverlässigen Netzwerk-FS ergeben. Das Programm zeigt eine Anfrage an, in der es den Benutzer auffordert, die CD erneut einzulegen, und bietet an, es erneut zu versuchen. Wenn der Benutzer sagt, was wiederholt werden muss, gibt der EXCEPTION_CONTINUE_EXECUTION
, und das Betriebssystem startet die Anweisung neu, bei der die Ausnahme aufgetreten ist.
Diesmal ist der Neustart erfolgreich, da die CD-ROM vorhanden ist (und gelesen wird) und der Code erfolgreich in den Speicher gepumpt werden kann. Die folgende Anweisung wird ausgeführt, die den Wert außerhalb der roten Zone in das ecx
. Dies ist jedoch nicht derselbe Wert, der von der vorherigen Anweisung gespeichert wurde, da die STATUS_IN_PAGE_ERROR
Ausnahme ihn überschreibt. Der Vergleich zeigt, dass die Daten unterschiedlich sind, und wir gehen zum panic
.
Wenn Sie die Daten auf dem Stapel speichern möchten, platzieren Sie sie dort korrekt: Reduzieren Sie zuerst den Stapelzeiger und speichern Sie dann den Wert im gültigen Teil des Stapels. Verstecken Sie keine Daten hinter der roten Zone, dieser Speicher kann jederzeit ohne Ihr Wissen geändert werden.