2010-12-26 12 views
2

Ich versuche, die folgende Funktion aufrufen:Aufruf LONGLONG RtlLargeIntegerDivide (LONGLONG, LONGLONG, LONGLONG *) in NASM (stdcall)

long long RtlLargeIntegerDivide(long long dividend, long long divisor, long long* pRemainder) 

in Assembler-Code (NASM). Es verwendet die Aufrufkonvention stdcall und gibt den Quotienten zurück. Dies sind die Spezifikationen:

Input: [EDX, EAX] (Dividend), [ECX, EBX] (Divisor)

Output: [EDX, EAX] (Quotient), [ECX, EBX] (Rest)

Wie gehe ich dabei vor? (Mein Hauptproblem ist nicht genau verstehen, EBP und ESP, und wie sie sich auf lokale Variablen beziehen.)

(Nein, das ist keine Hausaufgaben; Ich versuche, eine Wrapper-C-Laufzeitbibliothek zu implementieren.)

Vielen Dank!

Antwort

4

Im 32-Bit-Modus müssen Sie mit EBP überhaupt nicht auf lokale Variablen zugreifen, das ist nur ein Überbleibsel der Konvention aus 16-Bit-Zeiten und geht uns jetzt sowieso nichts an.

ESP ist Ihr Stack-Zeiger, ich nehme an, Sie wissen das. Sie können Speicherplatz für Ihre lokalen Variablen "reservieren", indem Sie ESP dekrementieren.

stdcall Aufrufkonvention verwendet den Stapel für das Argument übergeben. Sie sind in der normalen Reihenfolge, wenn sie auf dem Stapel sind, aber wenn Sie PUSH verwenden, bedeutet das, dass Sie sie umgedreht haben. Integrale Rückgabewerte sind in EAX (und bei Bedarf EDX). Die aufgerufene Funktion bereinigt die Argumente vom Stapel.

So sollte der folgende Code tun, was Sie wollen:

sub ESP, 8; make room for remainder 
push ESP ; pass pointer to remainder as argument 
push ECX 
push EBX ; pass divisor argument 
push EDX 
push EAX ; pass dividend argument 
call RtlLargeIntegerDivide 
; quotient returned in EDX:EAX 
; so just load remainder from stack 
pop EBX 
pop ECX 

+0

Schöne Antwort (für Geschwindigkeit, können Sie MOV statt PUSH/POP verwenden), danke! :) – Mehrdad