J
... ich schau hier grad mal vorbei und kann vielleicht noch nachträglich etwas zum allgemeinen Verständnis beitragen (die Ursprungsfrage sieht nämlich irgendwie nach dem üblichen Framepointer-Thema aus):
(1) Alle lokalen Variablen und aktuellen Parameter werden ja bekannterweise auf dem Stack abgelegt.
(2) Return-Programpointer natürlich ebenfalls.
(3) Zusätzlich wird bei Hochsprachen nach allgemeiner Compilerbau-Theorie und -Praxis i.d.R. noch zusätzlich ein sogenannter Framepointer benutzt. Dieser Framepointer zeigt auf den Anfang (oder alternativ Ende) des Bereichs im Stack, wo die lokalen Variablen im Stack liegen. Jetzt kann der Compiler alle Funktions-lokalen Variablen/Parameter relativ zu diesem Framepointer adressieren.
(4) Der Framepointer wird selbst im Stack abgelegt, und zwar wird jedesmal beim Aufruf/Eintritt in eine neue Funktion der alte Framepointer auf den Stack gepackt. Hierdurch gibt es eine Rückwärtsverkettung entgegengesetzt zur aktuellen Aufrufhierarchie. Im Prinzip könnte man hierüber auch auf lokale Variablen der zuletzt aufgerufenen Funktion zugreifen (und der darüber...). Wichtig ist der Framepointer aber insbesondere auch für folgende Eigenschaft:
Man kann beim Aufruf einer Funktion auch mehr (oder weniger) aktuelle Parameter mitgeben als im Funktionskopf als formale Parameter definiert sind. Dies wird bei Non-ANSI-C, bei manchen Systemaufrufen und im Zusammenhang mit varargs (z.B. beim printf) genutzt. Nur auf diese Art bekommt der Compiler zur Compile-Zeit es richtig hin, dass der Stack anschließend wieder richtig aufgeräumt wird. Man denke mal genau nach: (a) Die Anzahl der Parameter ist unterschiedlich, (b) beim Aufruf werden n Push-Operationen für die aktuellen Parameter gemacht, (c) beim Verlassen der Funktion baut der Compiler m Pop-Operationen für die formalen Parameter ein. => Das geht folglich schief, weil m != n und der Stackpointer an völlig falscher Position ist.
Wie gesagt, auch hierfür sorgt der Framepointer für ein vernünftiges Aufräumen, weil er auf den Anfang der lokalen Variablen/Parameter zeigt (muss man sich in etwa als Anfangsadresse der jeweils ersten Push-Operation vorstellen). Man macht jetzt keine Pop-Operationen mehr für die lokalen Variablen/Parameter, sondern versetzt nur den Stackpointer auf den Wert des aktuellen Framepointers und hat auf einen Schlag alles aufgeräumt.
Das ist nicht ganz einfach zu kapieren, weil hier natürlich auch nur ganz grob skizziert, und wäre mit einer Zeichnung natürlich wesentlich einfacher zu erklären, aber vielleicht klappt's auch bei genügend Nachdenken. Erklärt ist es sicherlich in entsprechenden Compilerbau-Büchern.
Richtig kapieren (und dauerhaft inhalieren) tut man das allerdings erst, wenn man selber mal einen Compiler gebaut hat...
Viel Spaß beim Grübeln
Jox
P.S.: An Stelle eines Framepointers gibt es auch eine andere Methode, die aber unüblich ist. Aber das ist ein anderes Thema und trägt sonst nur zur Verwirrung bei...