Wenn Sie C-Code kompilieren und die Assembly betrachten, wächst der Stack rückwärts wie folgt:
_main:
pushq %rbp
movl $5, -4(%rbp)
popq %rbp
ret
-4(%rbp)
- Bedeutet dies, dass der Basiszeiger oder der Stapelzeiger die Speicheradressen tatsächlich nach unten verschieben, anstatt nach oben zu gehen? Warum ist das so?
Ich wechselte $5, -4(%rbp)
zu $5, +4(%rbp)
, kompiliert und lief den Code , und es gab keine Fehler. Warum müssen wir also auf dem Speicherstapel immer noch rückwärts gehen?
-4(%rbp)
überhaupt nicht bewegt wird und+4(%rbp)
möglicherweise nicht funktioniert hat.malloc
der Haufen rückwärts wächstmain
er seinen RBP blockiert. Das ist sicher möglich. (Und ja, das Schreiben4(%rbp)
würde auf den gespeicherten RBP-Wert springen). Tatsächlich tut dies das Hauptmenü niemov %rsp, %rbp
, daher ist der Speicherzugriff relativ zum RBP des Anrufers , wenn dies das ist, was das OP tatsächlich getestet hat !!! Wenn dies tatsächlich von der Compiler-Ausgabe kopiert wurde, wurden einige Anweisungen ausgelassen!Antworten:
Ja, die
push
Anweisungen dekrementieren den Stapelzeiger und schreiben in den Stapel, währendpop
umgekehrt vom Stapel gelesen und der Stapelzeiger inkrementiert wird.Dies ist insofern etwas historisch, als bei Maschinen mit begrenztem Speicher der Stapel hoch und nach unten gewachsen war, während der Haufen niedrig und nach oben gewachsen war. Es gibt nur eine Lücke des "freien Speichers" - zwischen dem Heap & Stack, und diese Lücke wird gemeinsam genutzt, entweder kann man nach Bedarf in die Lücke hineinwachsen. Das Programm hat nur dann nicht genügend Arbeitsspeicher, wenn Stapel und Heap zusammenstoßen und kein freier Arbeitsspeicher mehr vorhanden ist.
Wenn der Stapel und der Haufen beide in die gleiche Richtung wachsen, gibt es zwei Lücken, und der Stapel kann nicht wirklich in die Lücke des Haufens hineinwachsen (das Gegenteil ist ebenfalls problematisch).
Ursprünglich hatten Prozessoren keine speziellen Anweisungen zur Stapelverarbeitung. Als jedoch die Hardware um Stapelunterstützung erweitert wurde, entwickelte sich dieses Muster nach unten, und Prozessoren folgen diesem Muster auch heute noch.
Man könnte argumentieren, dass auf einem 64-Bit-Computer genügend Adressraum vorhanden ist, um mehrere Lücken zuzulassen - und als Beweis sind mehrere Lücken zwangsläufig der Fall, wenn ein Prozess mehrere Threads hat. Dies ist zwar keine ausreichende Motivation, um Dinge zu ändern, da bei Systemen mit mehreren Lücken die Wachstumsrichtung wohl willkürlich ist, sodass Tradition / Kompatibilität den Ausschlag geben.
Sie müßten die CPU - Stack Handhabungsanweisungen ändern , um die Richtung des Stapels zu ändern, oder auch auf der Verwendung der gewidmet gibt nach oben drücken und knallend Anweisungen (zB
push
,pop
,call
,ret
, andere).Beachten Sie, dass die MIPS-Befehlssatzarchitektur kein dediziertes
push
&pop
hat. Daher ist es praktisch, den Stapel in beide Richtungen zu vergrößern. Möglicherweise möchten Sie dennoch ein Speicherlayout mit einer Lücke für einen einzelnen Thread-Prozess, aber möglicherweise vergrößern Sie den Stapel nach oben und den Heap abwärts. In diesem Fall ist für einige C- Varg- Codes möglicherweise eine Anpassung der Übergabe der Quell- oder Unter-der-Haube-Parameter erforderlich.(Da es in MIPS kein dediziertes Stack - Handling gibt, können wir Pre - oder Post - Increment oder Pre - oder Post - Decrement verwenden, um auf den Stack zu drücken, sofern wir die genaue Umkehrung zum Abspringen des Stacks verwenden und auch annehmen, dass Das Betriebssystem respektiert das gewählte Stack-Nutzungsmodell. In der Tat ist der MIPS-Stack in einigen eingebetteten Systemen und einigen Bildungssystemen aufwärts gewachsen.)
quelle
push
undpop
auf den meisten Architekturen, sondern auch das weitaus wichtige Interrupt-Handling,call
,ret
, und was auch immer hat backene in Interaktion mit dem Stapel.gets()
einestrcpy()
nicht eingebundene Funktion übergibt, verwendet die Rückgabe in diesen Bibliotheksfunktionen die überschriebene Rückgabeadresse. Derzeit mit abwärts wachsenden Stapeln ist es, wenn ihr Anrufer zurückkehrt.strcpy
), gibt es auf einem Bogen, in dem die Rücksprungadresse in einem Register gespeichert ist, keinen Zugriff, um die Rücksprungfunktion zu blockieren Adresse.In Ihrem speziellen System beginnt der Stapel mit einer hohen Speicheradresse und "wächst" nach unten zu einer niedrigen Speicheradresse. (Der symmetrische Fall von niedrig nach hoch existiert auch)
Und da du von -4 auf +4 gewechselt hast und es lief, heißt das nicht, dass es korrekt ist. Das Speicherlayout eines laufenden Programms ist komplexer und hängt von vielen anderen Faktoren ab, die möglicherweise dazu beigetragen haben, dass Sie bei diesem extrem einfachen Programm nicht sofort abgestürzt sind.
quelle
Der Stapelzeiger zeigt auf die Grenze zwischen zugewiesenem und nicht zugewiesenem Stapelspeicher. Wird es nach unten vergrößert, bedeutet dies, dass es auf den Anfang der ersten Struktur im zugewiesenen Stapelspeicher verweist , wobei andere zugewiesene Elemente an größeren Adressen folgen. Zeiger auf den Anfang der zugewiesenen Strukturen zeigen zu lassen, ist weitaus üblicher als umgekehrt.
Heutzutage gibt es auf vielen Systemen ein separates Register für Stapelrahmen , die etwas zuverlässig abgewickelt werden können, um die Aufrufkette herauszufinden, wobei der lokale variable Speicher dazwischenliegt. Die Art und Weise, wie dieses Stapelrahmenregister auf einigen Architekturen eingerichtet ist, führt dazu, dass es im Gegensatz zum Stapelzeiger davor hinter den lokalen Variablenspeicher zeigt. Die Verwendung dieses Stapelrahmenregisters erfordert dann eine negative Indizierung.
Beachten Sie, dass Stapelrahmen und ihre Indizierung ein Nebenaspekt kompilierter Computersprachen sind, sodass der Codegenerator des Compilers sich eher mit der "Unnatürlichkeit" befassen muss als mit einem schlechten Assembler-Programmierer.
Es gab also gute historische Gründe für die Auswahl von Stapeln, die nach unten wachsen sollten (und einige davon bleiben erhalten, wenn Sie in Assemblersprache programmieren und sich nicht um die Einrichtung eines geeigneten Stapelrahmens kümmern), aber sie sind weniger sichtbar.
quelle