MIPS: Relevante Verwendung für einen Stapelzeiger ($ sp) und den Stapel

9

Momentan studiere ich für meine Computerorganisation Midterm, und ich versuche, den Stapelzeiger und den Stapel vollständig zu verstehen. Ich kenne folgende Fakten, die das Konzept umgeben:

  • Es folgt dem First-In-Last-Out-Prinzip
  • Und das Hinzufügen von etwas zum Stack erfolgt in zwei Schritten:

    %Vor%

Was mich daran hindert, vollständig zu verstehen, ist, dass ich mir keine relevante, selbstverständliche Situation einfallen lassen kann, in der ich Daten mit einem Stapelzeiger suchen und / oder verfolgen möchte.

Könnte jemand das Konzept als Ganzes näher erläutern und mir einige nützliche Codebeispiele geben?

    
Connor Black 26.02.2013, 22:18
quelle

2 Antworten

18

Eine wichtige Verwendung von stack ist das Verschachteln von Subroutinenaufrufen.

Jede Subroutine kann eine Gruppe von Variablen lokal für diese Subroutine haben. Diese Variablen können bequem auf einem Stapel in einem Stapelrahmen gespeichert werden. Einige Aufrufkonventionen übergeben auch Argumente auf dem Stapel.

Die Verwendung von Unterprogrammen bedeutet auch, dass Sie den Anrufer im Auge behalten müssen, dh die Absenderadresse. Einige Architekturen haben einen dedizierten Stack für diesen Zweck, während andere implizit den "normalen" Stack verwenden. MIPS verwendet standardmäßig nur ein Register, aber in Nicht-Blatt-Funktionen (dh Funktionen, die andere Funktionen aufrufen) wird die Rückkehradresse überschrieben. Daher müssen Sie den ursprünglichen Wert speichern, normalerweise auf dem Stapel unter Ihren lokalen Variablen. Die Aufrufkonventionen können auch deklarieren, dass einige Registerwerte über Funktionsaufrufe hinweg erhalten bleiben müssen. Sie können sie in ähnlicher Weise mit dem Stack speichern und wiederherstellen.

Angenommen, Sie haben dieses C-Fragment:

%Vor%

Die MIPS-Assembly sieht dann möglicherweise so aus:

%Vor%     
Jester 26.02.2013, 23:11
quelle
6

Die MIPS-Aufrufkonvention erfordert, dass die ersten vier Funktionsparameter in den Registern a0 bis a3 und der Rest, falls es mehr gibt, auf dem Stapel liegen. Außerdem muss der Funktionsaufrufer vier Plätze auf dem Stapel für die ersten vier Parameter reservieren, obwohl diese in den Registern übergeben werden.

Wenn Sie also auf Parameter fünf (und weitere Parameter) zugreifen möchten, müssen Sie sp verwenden. Wenn die Funktion wiederum andere Funktionen aufruft und ihre Parameter nach den Aufrufen verwendet, muss sie a0 bis a3 in diesen vier Steckplätzen auf dem Stapel speichern, um zu verhindern, dass sie verloren gehen / überschrieben werden. Auch hier verwenden Sie sp , um diese Register in den Stack zu schreiben.

Wenn Ihre Funktion lokale Variablen hat und nicht alle in Registern behalten kann (wie wenn sie a0 bis a3 nicht behalten kann, wenn sie andere Funktionen aufruft), muss sie den On-Stack verwenden Platz für diese lokalen Variablen, was wiederum die Verwendung von sp erfordert.

Zum Beispiel, wenn Sie dies hatten:

%Vor%

seine Demontage wäre so etwas wie:

%Vor%

Siehe sp , um auf x5 zuzugreifen.

Und dann, wenn Sie Code wie folgt haben:

%Vor%

Dies ist, was es in der Disassembly nach der Kompilierung aussieht:

%Vor%

Ich hoffe, ich habe den Code kommentiert, ohne Fehler zu machen.

Beachten Sie also, dass der Compiler in der Funktion r16 und r17 verwendet, sie jedoch auf dem Stapel speichert. Da die Funktion eine andere aufruft, muss sie auch ihre Rücksprungadresse auf dem Stapel behalten, anstatt sie einfach in r31 zu behalten.

PS Denken Sie daran, dass alle Verzweigungs- / Sprungbefehle in MIPS den unmittelbar folgenden Befehl ausführen, bevor die Steuerung tatsächlich an einen neuen Speicherort übertragen wird. Das könnte verwirrend sein.

    
Alexey Frunze 26.02.2013 23:21
quelle

Tags und Links