Startseite > Ausstellung > Inhalt

Kontaktiere uns

Hinzufügen: Block 5, Fuqiang Technology Park, Zhugushi Straße, Wulian, Longgang 518116

Mob: + 86-13510459036

E-Mail: info@panadisplay.com

Zeigen Sie Register oder Datenstruktur an, um die Stapelrahmen der verschachtelten Funktionen in der Computerprogrammierung zu lokalisieren
Apr 22, 2017

Anrufstapel anrufen

In der Informatik ist ein Anrufstapel eine Stapeldatenstruktur , die Informationen über die aktiven Unterroutinen eines Computerprogramms speichert. Diese Art von Stack ist auch als Ausführungsstapel , Programmstapel , Steuerstapel , Laufzeitstapel oder Maschinenstapel bekannt und wird oft nur auf den "Stapel" verkürzt. Obwohl die Wartung des Anrufstapels für das ordnungsgemäße Funktionieren der meisten Software wichtig ist, sind die Details normalerweise versteckt und automatisch in hochrangigen Programmiersprachen . Viele Computer- Befehlssätze bieten spezielle Anweisungen zum Manipulieren von Stapeln.

Ein Anrufstapel wird für mehrere verwandte Zwecke verwendet, aber der Hauptgrund dafür ist, dass man den Punkt verfolgt, auf den jede aktive Unterroutine die Kontrolle zurücksenden soll, wenn sie die Ausführung beendet hat. Eine aktive Unterroutine ist eine, die aufgerufen wurde, aber noch die Ausführung abzuschließen ist, nach der die Kontrolle an den Punkt des Anrufs zurückgegeben werden soll. Solche Aktivierungen von Unterroutinen können auf jede Ebene (rekursiv als Spezialfall), also die Stapelstruktur, verschachtelt sein. Wenn z. B. eine Unterroutine DrawSquare eine Unterroutine DrawLine von vier verschiedenen Orten DrawLine muss DrawLine wissen, wo sie zurückkehren soll, wenn ihre Ausführung abgeschlossen ist. Um dies zu erreichen, wird die Adresse , die dem Anrufbefehl folgt, die Rücksendeadresse , mit jedem Anruf auf den Anrufstapel gedrückt.


Inhalt

[ Verstecken ]


Beschreibung [ bearbeiten ]

Da der Anrufstapel als Stapel organisiert ist, drückt der Anrufer die Rücksendeadresse auf den Stapel und die angerufene Unterroutine, wenn sie fertig ist, zieht oder kehrt die Rücksendeadresse aus dem Anrufstapel und überträgt die Steuerung an diese Adresse. Wenn eine angerufene Unterroutine eine weitere Unterroutine anruft, wird sie eine weitere Rücksendeadresse auf den Anrufstapel schieben, und so weiter, mit der Information, die sich stapelt und entstapelt, während das Programm diktiert. Wenn das Schieben den gesamten Platzbedarf für den Aufrufstapel verbraucht, tritt ein Fehler auf, der als Stapelüberlauf bezeichnet wird , was im Allgemeinen dazu führt, dass das Programm abstürzt . Das Hinzufügen eines Subroutineneintrags zum Anrufstapel wird manchmal als "Wicklung" bezeichnet; Umgekehrt ist das Entfernen von Einträgen "abwickeln".

Es gibt normalerweise genau einen Anrufstapel, der mit einem laufenden Programm (oder genauer gesagt mit jeder Aufgabe oder einem Thread eines Prozesses ) verbunden ist, obwohl zusätzliche Stapel für die Signalverarbeitung oder kooperative Multitasking (wie bei setcontext ) erzeugt werden können. Da es nur einen in diesem wichtigen Kontext gibt, kann er als Stapel bezeichnet werden (implizit "der Aufgabe"); In der Programmiersprache Forth wird jedoch der Datenstapel oder Parameterstapel expliziter als der Aufrufstapel zugegriffen und wird üblicherweise als Stapel bezeichnet (siehe unten).

In High-Level-Programmiersprachen sind die Besonderheiten des Call-Stacks in der Regel vom Programmierer verborgen. Sie erhalten nur Zugriff auf eine Reihe von Funktionen und nicht den Speicher auf dem Stapel selbst. Dies ist ein Beispiel der Abstraktion . Die meisten Assembler-Sprachen dagegen benötigen Programmierer, die mit der Manipulation des Stapels verbunden sind. Die tatsächlichen Details des Stapels in einer Programmiersprache hängen vom Compiler , Betriebssystem und dem verfügbaren Befehlssatz ab .

Funktionen des Anrufstapels [ bearbeiten ]

Wie oben erwähnt, besteht der primäre Zweck eines Anrufstapels darin, die Rücksendeadressen zu speichern . Wenn eine Unterroutine aufgerufen wird, muss die Stelle (Adresse) des Befehls, an der sie später wieder aufgenommen werden kann, irgendwo gespeichert werden. Die Verwendung eines Stacks zum Speichern der Rücksendeadresse hat gegenüber alternativen Aufrufkonventionen wichtige Vorteile. Einer ist, dass jede Aufgabe einen eigenen Stack haben kann, und so kann die Subroutine wiedereintrittsfähig sein , das heißt, kann gleichzeitig aktiv sein für verschiedene Aufgaben, die verschiedene Dinge tun. Ein weiterer Vorteil ist, dass die Rekursion automatisch unterstützt wird. Wenn sich eine Funktion rekursiv anruft, muss für jede Aktivierung der Funktion eine Rücksendeadresse gespeichert werden, damit sie später von der Funktionsaktivierung zurückkehren kann. Stack-Strukturen bieten diese Möglichkeit automatisch.

Abhängig von der Sprache, dem Betriebssystem und der Maschinenumgebung kann ein Anrufstapel zusätzliche Zwecke erbringen, zum Beispiel:

Lokale Datenspeicherung


Eine Subroutine benötigt häufig Speicherplatz für die Speicherung der Werte von lokalen Variablen , die Variablen, die nur innerhalb der aktiven Subroutine bekannt sind und keine Werte nach dem Zurückgeben beibehalten. Es ist oft bequem, Platz für diesen Gebrauch zuzuordnen, indem man einfach die Oberseite des Stapels durch genug bewegt, um den Raum zur Verfügung zu stellen. Dies ist sehr schnell im Vergleich zur dynamischen Speicherzuordnung , die den Haufenraum verwendet . Beachten Sie, dass jede einzelne Aktivierung eines Unterprogramms seinen eigenen separaten Platz im Stapel für Einheimische erhält.


Parameterübergabe


Subroutinen erfordern oft, dass Werte für Parameter ihnen durch den Code, der sie aufruft, geliefert werden, und es ist nicht ungewöhnlich, dass Platz für diese Parameter im Anrufstapel ausgelegt werden kann. Im Allgemeinen, wenn es nur wenige kleine Parameter gibt, werden Prozessorregister verwendet, um die Werte zu übergeben, aber wenn es mehr Parameter gibt, als dies auf diese Weise gehandhabt werden kann, wird Speicherplatz benötigt. Der Aufrufstapel funktioniert gut als Platz für diese Parameter, zumal jeder Aufruf einer Unterroutine, der unterschiedliche Werte für Parameter hat, für diesen Wert einen separaten Speicherplatz für den Aufrufstapel erhält.


Auswertungsstapel


Operanden für arithmetische oder logische Operationen werden am häufigsten in Register gesetzt und dort betrieben. In manchen Situationen können die Operanden jedoch bis zu einer beliebigen Tiefe gestapelt werden, was bedeutet, dass mehr als Register verwendet werden müssen (dies ist der Fall der Registerverschüttung ). Der Stapel solcher Operanden, wie der in einem RPN-Rechner , wird als Auswertestapel bezeichnet und kann Platz im Rufstapel einnehmen.


Zeiger auf aktuelle Instanz


Einige objektorientierte Sprachen (zB C ++ ) speichern diesen Zeiger zusammen mit Funktionsargumenten im Aufrufstapel beim Aufrufen von Methoden. Dieser Zeiger zeigt auf die Objektinstanz, die mit der aufzurufenden Methode verknüpft ist.


Umgang mit dem Unterprogramm Kontext


Einige Programmiersprachen (zB Pascal und Ada ) unterstützen die Deklaration von verschachtelten Subroutinen , die auf den Kontext ihrer umschließenden Routinen zugreifen können, dh die Parameter und lokalen Variablen im Rahmen der äußeren Routinen. Eine solche statische Verschachtelung kann sich wiederholen - eine Funktion, die innerhalb einer in einer Funktion deklarierten Funktion deklariert ist ... Die Implementierung muss ein Mittel darstellen, mit dem eine aufgerufene Funktion auf einer beliebigen statischen Verschachtelungsebene auf den umschließenden Rahmen auf jeder umschließenden Verschachtelungsstufe verweisen kann. Häufig wird diese Referenz durch einen Zeiger auf den Rahmen der zuletzt aktivierten Instanz der umschließenden Funktion, die so genannte "Downstack Link" oder "statische Verknüpfung", um sie von der "dynamischen Verknüpfung" zu unterscheiden, die sich auf den unmittelbaren Anrufer bezieht ( Die nicht die statische Elternfunktion sein müssen).


Anstelle einer statischen Verknüpfung können die Verweise auf die umschließenden statischen Rahmen in ein Array von Zeigern gesammelt werden, die als eine Anzeige bekannt sind, die indiziert ist, um einen gewünschten Rahmen zu lokalisieren. Die Tiefe einer routinemäßigen lexikalischen Nesting ist eine bekannte Konstante, so dass die Größe eines Routine-Displays fixiert ist. Auch die Anzahl der zu übertragenden Strecken ist bekannt, der Index in die Anzeige ist ebenfalls fixiert. Normalerweise befindet sich eine routinemäßige Anzeige in einem eigenen Stapelrahmen, aber die Burroughs B6500 implementiert eine solche Anzeige in Hardware, die bis zu 32 Stufen der statischen Verschachtelung unterstützt.


Die Anzeigeeinträge, die mit den Feldern versehen sind, werden aus dem entsprechenden Präfix der Anzeige des Anrufers erhalten. Eine innere Routine, die rekursiert, erzeugt für jeden Aufruf separate Anrufrahmen. In diesem Fall weisen alle statischen Verbindungen der inneren Routine auf denselben äußeren Routenkontext hin.


Anderer Rückkehrzustand


Neben der Rücksendeadresse können in einigen Umgebungen auch andere Maschinen- oder Softwarezustände vorhanden sein, die bei der Rückgabe eines Unterprogramms wiederhergestellt werden müssen. Dies könnte auch Dinge wie Privileg-Ebene, Exception-Handling-Informationen, Arithmetik-Modi und so weiter. Bei Bedarf kann dies im Anrufstapel gespeichert werden, so wie die Rücksendeadresse ist.


Der typische Aufrufstapel wird für die Rücksendeadresse, die Einheimischen und die Parameter (als Anrufrahmen bezeichnet ) verwendet. In einigen Umgebungen können dem Call Stack mehr oder weniger Funktionen zugeordnet werden. In der Programmiersprache Forth werden zum Beispiel gewöhnlich nur die Rücksendeadresse, gezählte Schleifenparameter und Indizes und ggf. lokale Variablen auf dem Aufrufstapel gespeichert (der in dieser Umgebung den Rückgabestapel genannt wird ), obwohl irgendwelche Daten vorübergehend platziert werden können Dort mit speziellem Return-Stack-Handling-Code, solange die Bedürfnisse von Anrufen und Rücksendungen eingehalten werden; Parameter werden normalerweise auf einem separaten Datenstapel oder Parameterstapel gespeichert, der in der Forth-Terminologie üblicherweise als Stapel bezeichnet wird, obwohl es einen Anrufstapel gibt, da er in der Regel explizit zugegriffen wird. Einige Forths haben auch einen dritten Stack für Gleitkommaparameter .

Struktur [ bearbeiten ]

Stapellayout aufrufen

Ein Anrufstapel besteht aus Stapelrahmen (auch Aktivierungsaufzeichnungen oder Aktivierungsrahmen genannt ). Dies sind maschinenabhängige und ABI- abhängige Datenstrukturen, die Subroutine-Zustandsinformationen enthalten. Diese Daten werden manchmal als CFI (Call Frame Information) bezeichnet. [1] Jeder Stapelrahmen entspricht einem Aufruf einer Unterroutine, die noch nicht mit einer Rückkehr beendet wurde. Wenn zum Beispiel eine Unterroutine namens DrawLine gerade ausgeführt wird, die von einer Unterroutine DrawSquare , könnte der obere Teil des Aufrufstapels wie im Bild auf der rechten Seite ausgelegt werden.

Ein solches Diagramm kann in beide Richtungen gezogen werden, solange die Platzierung der Oberseite und damit die Richtung des Stapelwachstums verstanden wird. Darüber hinaus unterscheiden sich die Architekturen unabhängig davon, ob Anrufstapel zu höheren Adressen oder zu niedrigeren Adressen hinaufwachsen. Die Logik des Diagramms ist unabhängig von der Adressierung Wahl.

Der Stapelrahmen an der Oberseite des Stapels ist für die aktuell laufende Routine. Der Stapelrahmen enthält in der Regel mindestens die folgenden Artikel (in Push-Reihenfolge):

  • Die Argumente (Parameterwerte) an die Routine übergeben (falls vorhanden);

  • Die Rücksendeadresse zurück zum Anrufer der Routine (zB im DrawLine Stack Frame, eine Adresse in DrawSquare 's Code); und

  • Platz für die lokalen Variablen der Routine (falls vorhanden).

Stapel- und Rahmenzeiger [ bearbeiten ]

Wenn Stapelrahmengrößen unterschiedlich sein können, z. B. zwischen verschiedenen Funktionen oder zwischen Aufrufen einer bestimmten Funktion, ist das Auftauchen eines Rahmens aus dem Stapel kein festes Dekrement des Stapelzeigers . Bei der Funktionsrückgabe wird der Stapelzeiger stattdessen wieder auf den Rahmenzeiger zurückgesetzt , wobei der Wert des Stapelzeigers kurz vor der Aufruf der Funktion Jeder Stapelrahmen enthält einen Stapelzeiger auf die Oberseite des Rahmens unmittelbar darunter. Der Stack-Pointer ist ein veränderliches Register, das zwischen allen Aufrufen geteilt wird. Ein Frame-Pointer eines gegebenen Aufrufs einer Funktion ist eine Kopie des Stack-Zeigers, wie es war, bevor die Funktion aufgerufen wurde. [2]

Die Orte aller anderen Felder im Rahmen können relativ zu der Oberseite des Rahmens, als negative Offsets des Stapelzeigers oder relativ zum oberen Rand des Rahmens, als positive Offsets des Rahmenzeigers definiert werden. Die Position des Rahmenzeigers selbst muss inhärent als negativer Versatz des Stapelzeigers definiert sein.

Speichern der Adresse an den Rahmen des Anrufers [ bearbeiten ]

In den meisten Systemen hat ein Stapelrahmen ein Feld, das den vorherigen Wert des Rahmenzeigerregisters enthält, den Wert, den er während des Aufrufs des Anrufers hatte. Zum Beispiel würde der DrawLine von DrawLine einen Speicherplatz haben, der den Frame-Pointer-Wert enthält, den DrawSquare verwendet (nicht in dem Diagramm oben gezeigt). Der Wert wird beim Eintritt in die Unterroutine gespeichert und bei Rückgabe wiederhergestellt. Wenn ein solches Feld an einer bekannten Stelle in dem Stapelrahmen vorhanden ist, kann der Code auf jeden Rahmen sukzessive unterhalb des momentan ausgeführten Routinenrahmens zugreifen und ermöglicht es der Routine, den Rahmenzeiger auf den Rahmen des Anrufers einfach wiederherzustellen, kurz bevor er zurückkehrt.

Lexisch verschachtelte Routinen [ bearbeiten ]

Weitere Informationen: Verschachtelte Funktion und Nicht-Lokale Variable

Programmiersprachen, die verschachtelte Unterroutinen unterstützen, haben auch ein Feld im Anrufrahmen, das auf den Stapelrahmen der letzten Aktivierung des Vorgangs verweist, das den Anklang am engsten kapselt, dh den unmittelbaren Bereich des Angerufenen. Dies nennt man eine Zugriffsverbindung oder eine statische Verknüpfung (da sie die statische Verschachtelung während dynamischer und rekursiver Anrufe beibehält) und die Routine (sowie alle anderen Routinen, die sie aufrufen kann) auf die lokalen Daten ihrer Einkapselungsroutinen bei jeder Verschachtelung aufgibt Ebene. Einige Architekturen, Compiler oder Optimierungsfälle speichern einen Link für jede umschließende Ebene (nicht nur die unmittelbar umschließenden), so dass tief verschachtelte Routinen, die auf flache Daten zugreifen, nicht mehrere Links durchlaufen müssen. Diese Strategie wird oft als "Display" bezeichnet. [3]

Access-Links können weg optimiert werden, wenn eine innere Funktion nicht auf irgendwelche (nicht konstante) lokale Daten in der Kapselung zugreift, wie es bei reinen Funktionen der Fall ist, die nur über Argumente und Rückgabewerte kommunizieren. Einige historische Computer, wie die Burroughs-Großsysteme , hatten spezielle "Display-Register", um verschachtelte Funktionen zu unterstützen, während Compiler für die meisten modernen Maschinen (wie die ubiquitous x86) einfach ein paar Worte auf den Stapel für die Zeiger, wie nötig.

Überlappen [ bearbeiten ]

Für einige Zwecke kann der Stapelrahmen einer Unterroutine und der seines Anrufers als überlappend betrachtet werden, wobei die Überlappung aus dem Bereich besteht, in dem die Parameter vom Anrufer zum Angerufenen übergeben werden. In einigen Umgebungen drückt der Anrufer jedes Argument auf den Stapel und erweitert damit seinen Stapelrahmen und ruft dann den Angriff auf. In anderen Umgebungen hat der Anrufer einen vorab zugeordneten Bereich an der Spitze seines Stapelrahmens, um die Argumente zu halten, die er an andere Unterroutinen liefert, die er anruft. Dieser Bereich wird manchmal als der ausgehende Argumentbereich oder der Callout-Bereich bezeichnet . Unter diesem Ansatz wird die Größe des Bereichs berechnet, indem der Compiler der größte ist, der von einem sogenannten Unterprogramm benötigt wird.

Verwenden Sie [ bearbeiten ]

Anrufbearbeitung bearbeiten [ bearbeiten ]

Normalerweise ist die Anrufstapelmanipulation, die an der Stelle eines Aufrufs zu einer Unterroutine benötigt wird, minimal (was gut ist, da es viele Anrufstellen für jede aufzurufende Unterroutine geben kann). Die Werte für die tatsächlichen Argumente werden an der Aufrufstelle ausgewertet, da sie für den jeweiligen Aufruf spezifisch sind und entweder auf den Stapel gedrückt oder in Register gesetzt werden, wie durch die verwendete Aufrufkonvention bestimmt . Der eigentliche Anrufbefehl, wie beispielsweise "Verzweigung und Verknüpfung", wird dann typischerweise ausgeführt, um die Steuerung an den Code der Zielunterroutine zu übertragen.

Subroutine Eintrag Verarbeitung [ bearbeiten ]

In der aufgerufenen Subroutine wird der erste ausgeführte Code gewöhnlich als Subroutinenprolog bezeichnet , da es die notwendige Housekeeping vor dem Code für die Anweisungen der Routine begonnen hat.

Der Prolog wird gewöhnlich die in einem Register verbleibende Rücksendeadresse durch den Anrufbefehl speichern, indem er den Wert auf den Anrufstapel drückt. In ähnlicher Weise können die aktuellen Stapelzeiger- und / oder Rahmenzeigerwerte gedrückt werden. Alternativ liefern einige Befehlssatzarchitekturen automatisch eine vergleichbare Funktionalität als Teil der Aktion des Anrufbefehls selbst, und in einer solchen Umgebung muss der Prolog dies nicht tun.

Wenn Rahmenzeiger verwendet werden, setzt der Prolog typischerweise den neuen Wert des Rahmenzeigerregisters aus dem Stapelzeiger. Platz auf dem Stapel für lokale Variablen kann dann durch inkrementelle Änderung des Stapelzeigers zugeordnet werden.

Die Programmiersprache Forth ermöglicht eine explizite Wicklung des Anrufstapels (dort den "Rückholstapel" genannt).

Rückgabe [ bearbeiten ]

Wenn eine Unterroutine bereit ist, zurückzukehren, führt sie einen Epilog aus, der die Schritte des Prologs rückgängig macht. Dies wird typischerweise gespeicherte Registerwerte (wie z. B. den Frame-Pointer-Wert) aus dem Stack-Frame wiederherstellen, den gesamten Stack-Frame aus dem Stack ausbilden, indem er den Stack-Pointer-Wert ändert und schließlich zu der Anweisung an der Rücksendeadresse verzweigt. Unter vielen anrufenden Konventionen tauchten die Gegenstände aus dem Stapel durch den Epilog auf, die ursprünglichen Argumentwerte, in welchem Fall es in der Regel keine weiteren Stackmanipulationen gibt, die vom Anrufer gemacht werden müssen. Bei einigen anrufenden Konventionen ist es jedoch Aufgabe des Anrufers, die Argumente aus dem Stack nach der Rückgabe zu entfernen.

Abwicklung [ bearbeiten ]

Wenn Sie von der aufgerufenen Funktion zurückkehren, wird das obere Bild aus dem Stapel gelegt, vielleicht einen Rückgabewert hinterlassen. Der allgemeinere Akt des Aufspringens eines oder mehrerer Frames aus dem Stack, um die Ausführung an anderer Stelle im Programm wieder aufzunehmen, heißt Stapelabwicklung und muss durchgeführt werden, wenn nicht-lokale Steuerungsstrukturen verwendet werden, wie jene, die für die Ausnahmebehandlung verwendet werden . In diesem Fall enthält der Stapelrahmen einer Funktion einen oder mehrere Einträge, die Ausnahmehandler angeben. Wenn eine Ausnahme ausgelöst wird, wird der Stapel abgewickelt, bis ein Handler gefunden wird, der bereit ist, den Typ der geworfenen Ausnahme zu behandeln (zu fangen)

Einige Sprachen haben andere Kontrollstrukturen, die eine allgemeine Abwicklung erfordern. Pascal erlaubt eine globale goto- Anweisung, um die Steuerung aus einer verschachtelten Funktion und in eine zuvor aufgerufene äußere Funktion zu übertragen. Dieser Vorgang erfordert, dass der Stapel abgewickelt wird, wodurch so viele Stapelrahmen entfernt werden, wie es notwendig ist, um den richtigen Kontext wiederherzustellen, um die Steuerung auf die Zielanweisung innerhalb der umschließenden äußeren Funktion zu übertragen. Ähnlich hat C die setjmp und longjmp Funktionen, die als nicht-lokale gotos fungieren. Common Lisp erlaubt die Kontrolle über das, was passiert, wenn der Stapel abgewickelt wird, indem er den unwind-protect special operator benutzt.

Bei der Anwendung einer Fortsetzung wird der Stapel (logisch) abgewickelt und dann mit dem Stapel der Fortsetzung zurückgespult. Dies ist nicht der einzige Weg, um Fortsetzungen zu setzen; Zum Beispiel, mit mehreren, expliziten Stacks, Anwendung einer Fortsetzung kann einfach aktivieren Sie seinen Stack und Wind einen Wert zu übergeben. Die Scheme-Programmiersprache erlaubt es, beliebige Thunks in bestimmten Punkten beim "Abwickeln" oder "Zurückspulen" des Kontrollstapels auszuführen, wenn eine Fortsetzung aufgerufen wird.

Inspektion [ bearbeiten ]

Siehe auch: Profiling (Computerprogrammierung)

Der Anrufstapel kann manchmal bei laufendem Programm überprüft werden. Abhängig davon, wie das Programm geschrieben und kompiliert wird, können die Informationen über den Stack verwendet werden, um Zwischenwerte und Funktionsaufrufspuren zu ermitteln. Dies wurde verwendet, um feinkörnige automatisierte Tests zu generieren, [4] und in Fällen wie Ruby und Smalltalk, um erstklassige Fortsetzungen zu implementieren. Als Beispiel implementiert der GNU Debugger (GDB) eine interaktive Inspektion des Anrufstapels eines laufenden, aber pausierten C-Programms. [5]

Wenn Sie regelmäßig Zeitproben des Anrufstapels verwenden, kann es sinnvoll sein, die Leistung von Programmen zu profilieren, denn wenn der Zeiger eines Unterprogramms auf den Aufrufstapel-Abtastdaten viele Male erscheint, ist es wahrscheinlich ein Code-Engpass und sollte auf Leistungsprobleme überprüft werden.

Sicherheit [ bearbeiten ]

Hauptartikel: Stapelpufferüberlauf

In einer Sprache mit freien Zeigern oder nicht geprüften Array-Schreibvorgängen (z. B. in C) wird das Mischen von Steuerflussdaten, die die Ausführung von Code (die Rücksendeadressen oder die gespeicherten Rahmenzeiger) und einfache Programmdaten (Parameter oder Rückgabewerte) beeinflussen ) In einem Call-Stack ist ein Sicherheitsrisiko, möglicherweise ausnutzbar durch Stack-Puffer überläuft als die häufigste Art von Puffer überläuft .

Einer dieser Angriffe beinhaltet das Füllen eines Puffers mit beliebigem ausführbaren Code und überbrückt dann denselben oder einen anderen Puffer, um eine Rücksendeadresse mit einem Wert zu überschreiben, der direkt auf den ausführbaren Code zeigt. Als Ergebnis, wenn die Funktion zurückkehrt, führt der Computer diesen Code aus. Diese Art von Angriff kann leicht mit W ^ X blockiert werden. [ Zitieren benötigt ] Ähnliche Angriffe können auch mit W ^ X-Schutz aktiviert werden, einschließlich des Return-to-libc-Angriffs oder der Angriffe, die von der zurückkehrenden Programmierung kommen . Es wurden verschiedene Abhilfemaßnahmen vorgeschlagen, wie z. B. das Speichern von Arrays an einer völlig getrennten Stelle aus dem Rücklaufstapel, wie dies in der Programmiersprache Forth der Fall ist. [6]