Ich spiele mit gcc -S
herum, um zu verstehen, wie Speicher und Stack funktionieren. Während dieser Stücke fand ich einige Dinge unklar. Könnten Sie mir bitte helfen, die Gründe zu verstehen?
Beim Aufruf von function sets Argumente für einen aufgerufenen verwendet es mov
bis esp
anstatt push
. Was ist der Vorteil, wenn Sie push
nicht verwenden?
Die Funktion, die mit ihren Stack-basierten Argumenten arbeitet, zeigt auf sie als ebp + (N + offset)
(wobei N eine für die Rückgabeadresse reservierte Größe ist). Ich erwarte esp - offset
, was verständlicher ist. Was ist der Grund dafür, ebp
als fundamentalen Punkt überall zu verwenden? Ich weiß, dass diese gleich sind, aber trotzdem?
Wofür ist diese Magie am Anfang von main
? Warum muss esp
nur auf diese Weise initialisiert werden?
Danke,
Ich nehme an, dass Sie in einer 32-Bit-Umgebung arbeiten, da in einer 64-Bit-Umgebung Argumente in Registern übergeben werden.
Frage 1
Vielleicht übergeben Sie hier ein Gleitkomma Argument. Sie können diese nicht direkt drücken, da die Anweisung push
in einer 32-Bit-Laufzeit 4 Bytes gleichzeitig verschiebt, so dass Sie den Wert aufteilen müssen. Es ist manchmal einfacher, 8 von esp
zu subtrahieren, und sie bewegen das 8-Byte-Vierwort in [esp]
.
Frage 2
ebp
wird häufig zum Indizieren der Parameter und Locals in Stack-Frames in 32-Bit-Code verwendet. Dadurch können die Offsets innerhalb von Frames auch dann fixiert werden, wenn sich der Stapelzeiger bewegt. Betrachten Sie zum Beispiel
Wenn Sie jetzt nur auf den Stapelrahmeninhalt mit esp
zugreifen, dann ist a
auf [esp]
, die Rückgabeadresse wäre [esp+4]
und x
wäre [esp+8]
. Jetzt generieren wir Code zum Aufruf von g
. Wir müssen zuerst 5 drücken und dann x
drücken. Aber nach dem Drücken von 5 hat sich der Offset von x
von esp
geändert! Deshalb wird ebp
verwendet. Normalerweise schieben wir bei der Eingabe von Funktionen den alten Wert von ebp
, um ihn zu speichern, und kopieren dann esp
in ebp
. Jetzt kann ebp
verwendet werden, um auf Stapelrahmeninhalte zuzugreifen. Es wird sich nicht bewegen, wenn wir uns in der Mitte der Argumente befinden.
Frage 3
Diese and
Anweisung löscht die letzten 4 Bits von esp
und richtet sie auf eine 16-Byte Grenze aus. Da der Stack nach unten wächst, ist das schön und sicher.