__fastcall



  • __fastcall

    Was bedeutet das genau?



  • Steht doch in der Hilfe! Registerdingsbums für anderes Dingsda!



  • Hm, ist vielleicht ein wenig mager erklärt.

    Ich versuchs mal.

    Siehe Bild:
    http://www.directupload.net/show_image.php?d=138&n=579FcDz7.jpg

    Fangen wir ein wenig mit Theorie an. Es gibt ein paar verschiedene Art und Weisen, in denen Funktionen aufgerufen werden können. Diese möchte ich nun kurz anschneiden:

    1. C-Call (cdecl-Call)

    Das ist die gängigste Methode eine Funktion aufzurufen. Die Methode f() wird mit dieser Aufrufsmethode aufgerufen. Dabei werden die Parameter in umgekehrter reihenfolge auf dem Stack gepackt:

    push ox03
    push ox02
    push ox01
    

    nun erfolgt der Methodenaufruf mit

    call f(int, int, int)
    

    In der Methdoe F() müssen nun die Parameter ausgelesen werden.
    Dafür wird meist erst einmal eine Variable geschaffen (den Basepointer), den wir auf den ersten Eintrag auf dem Stack zeigt. Dafür nimmt man esp

    push EBP
    mov ebp,esp
    

    Da die Parameter nun auf dem Stack liegen, kann man anhand des Basepointers, die relative Adresse absehen und den Parameter verwenden. Dieser fängt in der Regel bei 0X08 an.

    Hier werden also die Parameter ausgelesen. In der Funktion werden die Parameter wiederum auf dem Stack gelegt, weil wir ja die Methode hier wieder aufrufen (rekursiv):

    Push dword ptr [ebp+0x10]
    Push dword ptr [ebp+0x0c]
    Push dword ptr [ebp+0x08]
    

    Wie man sieht wieder in umgekehrter Reihenfolge.
    Nach dem Aufruf wird unser Basiszeiger noch eben vom Stack geholt und zur Main() zurückgesprungen. Dort muss noch der Stackpointer für den vorherigen Aufruf wieder zurückgesetzt werden.

    Das geschiet mit

    add esp, 0x0c
    

    Das ist ein vollständiger C-Call- Funktionsablauf.

    2. Standard-Call-Aufruf

    Dieses kennen wir von stdcall aus der WINAPI. Der unterschied zum cdecl-Call ist, dass die Funktion selbst den Stackpointer zurücksetzen muss.
    Das kann man in der funktion W() sehen:

    ret 0x000c

    hier wird beim Rücksprung der Stackpointer zurückgesetzt.
    Wie man an der Main-Methode sieht, wird kein add, „esp,0x0c“ aufgerufen.
    Hat den Vorteil, dass die aufrufende Methode aufgeräumter ist.

    3. Fastcall-Aufruf

    Hierbei werden die Parameter der Methode nicht auf dem Stack geschoben, sondern direkt in Register geschrieben, die lesend von der Methode verwendet werden können.

    Hier werden die Register ecx, edx, eax geschrieben:

    Mov ecx,0x000000003
    Mov edx,0x000000003
    Mov eax,0x000000003
    

    Nun erfolgt der Methodenaufruf und in der Methode kann die Methode die Parameter einfach über die Register lesen.

    Mov[ebp-0xoc],ecx
    Mov[ebp-0x08],edx
    Mov[ebp-0x04],eax
    

    Nun ist aber das Problem, das der Compiler von Borland da irgendwie Mist baut.
    Um die Methode m() (rekursiv) in der Methode m() aufzurufen schiebt er die Parameter wieder in die Register. Das ist normalerweise Quatsch. Aber egal, kann ja daran liegen, dass die Methode selbst auch Schwachsinn ist. Aber es zeigt die Unterschiede. Und nur das zählt.

    __fastcall ist also (theoretisch) schneller, weil direkt auf die Register geschrieben wird und nicht die Parameter auf dem Stak gepush werden müssen.


Anmelden zum Antworten