2009-08-09 14 views
8

Ich habe gerade angefangen mit ASM zu basteln und ich bin mir nicht sicher, ob mein Verständnis von Prozeduraufrufen korrekt ist.Wie funktionieren Prozeduraufrufe in Assembler?

irgendwann sagen, im Code gibt es einen Prozeduraufruf

call dword ptr[123] 

und das Verfahren besteht aus nur einem Befehl, ret:

ret 0004 

was die Wirkung dieser Prozeduraufruf wäre und wo würde der Rückgabewert gespeichert? Ich habe irgendwo gelesen, dass ein Rückgabewert von 2 Bytes würde in AX gespeichert werden, aber wenn ich den Prozeduraufruf ersetzen durch

mov AX, 0004 

(zusammen mit den notwendigen NOPs) das Programm abstürzt.

Antwort

12

in x86-Assembler der Parameter auf die ret Anweisung bedeutet:

RET immediate

Zurück zur Prozedur aufrufen und Pop sofort Bytes vom Stapel.

(Zitat aus Intel® 64 and IA-32 Architectures Software Developer's ManualsVol 2B)

Also, wenn Sie ein:

ret 0004 

Sie sagen die CPU auf die Anweisung zurückzukehren unmittelbar nach dem call und 4 Bytes aus Pop der Stapel. Dies ist großartig, wenn Sie geschoben 4 Bytes auf den Stapel vor dem Anruf.

push eax 
call dword ptr[123] 

Beachten Sie, dass dies nichts mit dem Rückgabewert zu tun hat. In der Tat kann eine Prozedur in Assembly nicht angeben, dass ein Wert return Wert ist. Dies geschieht alles durch Konvention. Die meisten Compiler, von denen ich weiß, verwenden EAX, um den Rückgabewert zu halten, aber dies ist nur wahr, weil die Aufruf Funktion das Ergebnis dort erwarten wird.

So würde Ihre Berufung Code sein:

call dword ptr [123] 
mov dword ptr [result], eax 

und Ihre Funktion, die den Wert 4 wäre zurückgibt:

mov eax, 4 
ret 
+0

danke! die meisten der Tutorials, die ich gegoogelt habe, benutzten nur ret und erklärten nicht die Operation sofort. Ich wurde weiter verwirrt, als der LLVM-Assembler anscheinend einen "ret " Befehl hatte. – int3

+0

Gibt es einen Grund, warum RET zu einem anderen Ort als dem Aufrufer zurückkehren kann? Ich habe gerade eine Frage erstellt und diese in verwandten Fragen gefunden – lisovaccaro

+0

ja, wenn Sie die Absenderadresse manipuliert, die 'CALL' auf den Stapel geschoben. –

-1

Ich glaube nicht, dass der Rückgabewert im AX-Register gespeichert wird

+0

irgendeine Idee wo, dann? – int3

+0

@ int3: Es hängt von der Aufrufkonvention ab. Hier ist nichts automatisch. Die aufrufende Funktion und die aufgerufene Funktion müssen übereinstimmen, wo der Rückgabewert ist. –

1
// possibly there are arguments pushed here 
... 
call dword ptr[123] // push next OP code offset in the stack and jump to procedure 

// procedure 
... 
ret 0004 // pop offset, set EIP to that offset and decrease ESP by 4 

wir zusätzlich das ESP ab, wenn wir Argumente in dem Stapel vor dem Aufruf der Prozedur geschoben hatte.


Wenn es Push Argumente gibt, stürzt Ihr Programm ab, weil Sie sie nicht pop. Der Rückgabe-Offset für die aktuelle Prozedur ist falsch, da er einen Wert von einem der Push-Argumente als Offset erhält.

2

Alles auf der calling convention hängt verwendet wird. Ich werde den Wikipedia-Artikel hier nicht wiederholen, lesen Sie einfach die Definition.

In der C calling convention zum Beispiel wäre der Rückgabewert in EAX/AX/AL. Ihre Einzelinstruktion hat keine: Sie ist eine void-Funktion, die ungefähr 4 Bytes von Parametern (möglicherweise ein einzelnes int) benötigt, die nichts tun. Da es die Pflicht des Angerufenen ist, den Stapel in dieser Aufrufkonvention zu bereinigen, funktioniert das Ignorieren, dies zu tun und den Aufruf durch eine "mov ax" zu ersetzen, nicht.

Auch ich vermute, dass Sie möglicherweise mit 32-Bit-Assembly beim Lesen eines 16-Bit-Dokuments basteln. Es ist kein großes Problem, aber Sie sollten sich der Unterschiede bewusst sein.