2010-03-30 6 views
7

Dies ist, was ich von disassemble für die Anweisung siehe function(1,2,3);:Wie wird die Rücksendeadresse im Stapel angegeben?

movl $0x3,0x8(%esp) 
movl $0x2,0x4(%esp) 
movl $0x1,(%esp) 
call 0x4012d0 <_Z8functioniii> 

Es scheint, die ret Adresse nicht gedrückt in den Stack überhaupt, dann wie funktioniert ret Arbeit?

Antwort

3

Es hängt von der ABI und der Architektur ab, aber wenn die Rücksprungadresse auf dem Stapel landet, ist es ein Nebeneffekt der call Anweisung, die es dort setzt.

5

Idealerweise sollte die call Anweisung dafür sorgen. Der nächste Ort des Programmzählers wird in den Stapel geschoben. Wenn die Funktion (Unterroutine), die aufgerufen wurde, ihre Arbeit beendet und wenn sie auf eine return-Anweisung stößt, geht das Steuerelement nun zu der Adresse, die in den Stapel geschoben wurde, und es wird angezeigt.

+1

hilft Wie damit nicht 'call' Deal dann? ich will nur sehen, wo die * ret-Adresse * ist angegeben – Mask

+0

Sie haben die Aufrufmethode auf weiteren Hex-Code aufgeteilt. Der Spickzettel für den Befehlssatz, der für den bestimmten Prozessor spezifiziert ist, würde dies offenbaren. Zum Beispiel, wenn Sie die einfachsten Mikroprozessoren 8085 nehmen und ADD X Anweisung zeigt nicht den zweiten Wert (nehmen wir an, Y wie ADD X, Y). Statt dessen wird der Wert X zu einem reservierten Register innerhalb des Prozessors hinzugefügt und der Wert in H gespeichert. Das Überlaufbit, falls es vorhanden ist, wird in einem anderen Register gespeichert. So wird die ADD-Anweisung entworfen. CALL-Anweisung wird auch ähnliche vordefinierte Regeln haben – bragboy

+5

Teil des Auftrags der Aufrufanweisung ist, die Rücksprungadresse auf den Stapel zu schieben. Die Rücksprungadresse ist nur die Adresse direkt nach den Parametern der Aufrufanweisung. Um zu sehen, was die Rücksprungadresse in obigem Beispiel ist, müssten Sie sich den Stack anschauen, sobald das Programm bei 0x4012d0 in die Prozedur gelangt. –

4

Auf einem x86-Prozessor (wie für Ihre Assemblersprache Beispiel) drückt die call Anweisung die Rücksprungadresse auf dem Stapel und übergibt die Kontrolle an die Funktion.

Nicht alle Prozessorarchitekturen setzen die Rücksprungadresse auf den Stapel - oft gibt es einen Satz von einem oder mehreren Registern, die Rückadressen enthalten. Bei ARM-Prozessoren platziert die BL-Anweisung die Rücksprungadresse in einem bestimmten Register (LR oder das "Link-Register") und übergibt die Steuerung an die Funktion. Der ia64-Prozessor tut etwas Ähnliches, außer dass es mehrere mögliche Register gibt (b0 - b7), die die Rücksendeadresse empfangen können und eine wird in der Anweisung angegeben (wobei b0 die Standardeinstellung ist).

1

Anruf drückt den aktuellen Wert des RIP-Registers (Rückkehradresse) an den Stapel + wird der Anruf
ret die Rücksprungadresse erscheint (die Anruf geschoben) von der Oberseite des Stapels (RSP registriert dort Punkte) und schreibt sie in das RIP-Register.

Beispiel für eine GNU/Linux-Box: Funktion f ruft die Funktion g auf und lässt uns den Rahmen von g betrachten.

niederwertige Adresse

... < - RSP (Stack-Zeiger oben auf dem Stack zeigt) registrieren Punkte an dieser Adresse
g lokalen Vars
des f-Basiszeiger (alte RBP-Wert) < - RBP (Basiszeiger) registrieren Punkte an dieser Adresse
f der ret-Adresse (alt RIP-Wert) (das ist, was der Aufruf (von f) gedrückt wird, und das, was die ret (von g) wird angezeigt)
args das f mit g angerufen hat und nicht in die register passte (ich denke unter Windows ist das anders)
...

hohe Adresse

g werden die lokalen Vars (movq% rsp,% RBP) kostenlos
g wird die "alte RBP" Pop und speichern sie in RBP-Register (pop% RBP)
g wird ret, die RIP mit dem Wert ändern wird, die in der RSP Punkt auf

gespeichert Hoffen, dass es