Ich versuche zu verstehen, wie Stapelrahmen erstellt werden und welche Variablen (Parameter) in welcher Reihenfolge zum Stapeln verschoben werden. Einige Suchergebnisse haben gezeigt, dass der C / C ++ - Compiler basierend auf Operationen entscheidet, die innerhalb einer Funktion ausgeführt werden. Wenn die Funktion beispielsweise einen übergebenen int-Wert nur um 1 erhöhen und zurückgeben sollte (ähnlich dem ++ - Operator), würden alle Parameter der Funktion und der lokalen Variablen in Register eingetragen.
Ich frage mich, welche Register für die Rückgabe oder Übergabe von Wertparametern verwendet werden. Wie werden Referenzen zurückgegeben? Wie wählt der Compiler zwischen eax, ebx, ecx und edx?
Was muss ich wissen, um zu verstehen, wie Register, Stapel- und Heap-Referenzen während Funktionsaufrufen verwendet, erstellt und zerstört werden?
Antworten:
Zusätzlich zu dem, was Dirk sagte, besteht eine wichtige Verwendung von Stapelrahmen darin, vorherige Werte von Registern zu speichern, damit sie nach einem Funktionsaufruf wiederhergestellt werden können. Selbst auf Prozessoren, in denen Register zum Übergeben von Parametern, Zurückgeben eines Werts und Speichern der Rückgabeadresse verwendet werden, werden die Werte dieser Register vor einem Funktionsaufruf auf dem Stapel gespeichert, sodass sie nach dem Aufruf wiederhergestellt werden können. Auf diese Weise kann eine Funktion eine andere aufrufen, ohne ihre eigenen Parameter zu überschreiben oder ihre eigene Rücksprungadresse zu vergessen.
Das Aufrufen einer Funktion B von Funktion A auf einem typischen "generischen" System kann daher die folgenden Schritte umfassen:
Dies ist keineswegs die einzige Möglichkeit, wie Funktionsaufrufe funktionieren können (und ich habe möglicherweise ein oder zwei Schritte in der falschen Reihenfolge), aber es sollte Ihnen eine Vorstellung davon geben, wie der Stapel verwendet wird, damit der Prozessor verschachtelte Funktionsaufrufe verarbeitet.
quelle
push
undpop
sind die beiden Grundoperationen auf einem Stapel. Ein Stapel ist wie ein Stapel Bücher eine Last-In-First-Out-Struktur. Wenn Sie diespush
tun, legen Sie ein neues Objekt auf den Stapel. wenn Siepop
ein Objekt von der Oberseite des Stapels nehmen. Es ist nicht erlaubt, Objekte in der Mitte einzufügen oder zu entfernen. Sie können nur auf der Oberseite des Stapels arbeiten. Weitere Informationen zu Stacks im Allgemeinen und zum Programmstack im Besonderen finden Sie auf Wikipedia.Dies hängt von der verwendeten Aufrufkonvention ab. Wer die Aufrufkonvention definiert, kann diese Entscheidung nach Belieben treffen.
In der gängigsten Aufrufkonvention für x86 werden Register nicht zum Übergeben von Parametern verwendet. Die Parameter werden beginnend mit dem Parameter ganz rechts auf den Stack übertragen. Der Rückgabewert wird in eax platziert und kann edx verwenden, wenn es zusätzlichen Platz benötigt. Verweise und Zeiger werden in Form einer Adresse in eax zurückgegeben.
quelle
Wenn Sie Stack sehr gut verstehen, werden Sie verstehen, wie Speicher in einem Programm funktioniert, und wenn Sie verstehen, wie Speicher in einem Programm funktioniert, werden Sie verstehen, wie Funktionen in einem Programm gespeichert werden, und wenn Sie verstehen, wie Funktionen in einem Programm gespeichert werden, werden Sie verstehen, wie rekursive Funktionen funktionieren und wenn Sie verstehen, wie die rekursive Funktion funktioniert. Sie werden verstehen, wie der Compiler funktioniert. Wenn Sie verstehen, wie der Compiler funktioniert, werden Ihre Gedanken als Compiler arbeiten und Sie werden jedes Programm sehr einfach debuggen
Lassen Sie mich erklären, wie der Stack funktioniert:
Zuerst müssen Sie wissen, wie Funktionen im Stack gespeichert werden:
Werte für die dynamische Speicherzuweisung im Heapspeicher. Stapeln Sie die automatischen Zuordnungs- und Löschwerte.
Verstehen wir anhand eines Beispiels:
Verstehe nun Teile dieses Programms:
Nun wollen wir sehen, was Stapel ist und was Stapelteile sind:
Denken Sie daran, dass eine Funktion, wenn sie "return" erhält, unabhängig davon, ob sie alle ihre lokalen Variablen geladen hat, oder alles, was sie sofort vom Stapel zurückgibt, in den Stapelrahmen zurückkehrt. Wenn eine rekursive Funktion eine Grundbedingung erhält und die Rückgabe nach der Grundbedingung erfolgt, wartet die Grundbedingung nicht darauf, lokale Variablen zu laden, die sich im Programmteil "else" befinden, sondern gibt sofort den aktuellen Frame vom Stapel und jetzt einen Frame zurück Das nächste Bild wird im Aktivierungsdatensatz angezeigt. Sehen Sie dies in der Praxis:
Wenn also eine Funktion eine return-Anweisung gefunden hat, wird der aktuelle Frame vom Stapel gelöscht.
Wenn Sie vom Stapel zurückkehren, wird der Wert in umgekehrter Reihenfolge zurückgegeben, in der er im Stapel zugewiesen wurde.
Dies ist eine sehr kurze Beschreibung. Wenn Sie mehr über Stapel und doppelte Rekursion erfahren möchten, lesen Sie zwei Beiträge in diesem Blog:
Mehr über das Stapeln Schritt für Schritt
Mehr zu Doppelrekursion Schritt für Schritt mit Stack
quelle
Was Sie suchen, heißt Application Binary Interface - ABI.
Für jeden Compiler gibt es eine Spezifikation, die die ABI beschreibt.
Jede Plattform wird normalerweise eine ABI angeben, um die Interoperabilität zwischen Compilern zu unterstützen. Beispielsweise werden in x86- Aufrufkonventionen die typischen Aufrufkonventionen für x86 und x86-64 beschrieben. Ich würde jedoch ein offizielleres Dokument als Wikipedia erwarten.
quelle