Innline Assembler Zugriff auf globale C-Variablen



  • Hallo Leute,
    Ich möchte zur Laufzeit bestimmen ob die DLL-Funktion die ich aufrufe _stdcall oder _cdecl calling convention unterstützt. Ich habe zu diesem Problem hier im Forum schon einmal nachgefragt.
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-227797.html
    Da ich von Assembler nix verstehe scheitere ich schon recht schnell bei der Umsetzung. Ich verwende Visual Studio und komme jetzt mit Hilfe von MSDN nicht weiter. Das Problem ich weiß nicht wie ich die globalen C-Variablen auf den Stack bekomme. Mein Code sieht bisher so aus.
    [code]
    void (*MyDLLFunction)(float *var1, int *var2, char *var3, char *var4, char *var5) = NULL;
    ....

    void *var;

    __asm
    {
    mov var, esp
    mov dword eax, _V
    push eax
    mov eax, offset _avcOutname
    push eax
    mov eax, offset _accInfile
    push eax
    mov eax, offset _aviFail
    push eax
    mov eax, offset _V
    push eax

    call DLLFunc
    //Vergleich Stack und var (ob Stack wie zu beginn)
    cmp esp, var
    je stdcall
    mov Switch, 0 //false _cdecl
    pop ebx
    pop ebx
    pop ebx
    pop ebx
    pop ebx
    jmp end
    stdcall: //true _stdcall
    mov Switch, 1
    end:
    }



  • Jetzt habe ich versehentlich den Beitrag schon gesendet obwohl ich noch nicht fertig war.
    Also hier nochmal mein Code.

    ....
    void (*MyDLLFunction)(float *var1, int *var2, char *var3, char *var4, char *var5);
    ...
    
    void *var;
    int Switch = 0;
    
    __asm
       {
        mov var, esp
        push var5
        push var4
        push var3
        push var2
        push var1
    
        call  MyDLLFunction
        cmp esp, var
        je stdcall
        mov Switch, 0 //false _cdecl
        pop  ebx
        pop  ebx
        pop  ebx
        pop  ebx
        pop  ebx
        jmp end
        stdcall:			//true _stdcall
        mov Switch, 1
        end:
       }
    ...
    

    Mein Problem ist das ich die globalen Variablen (var1 - var5) nicht richtig auf den Stack bekomme. Oder besser gesagt ich weiß nicht wie das funktioniert. Wenn ich die Funktion mit call aufrufe stimmen die Speicheradressen meiner Argumente auch nicht so wirklich. Vielleicht kann mir jemand erklären wie ich die verschiedenen Typen meiner globalen Variablen auf den Stack bekomme.
    Vielen Dank

    Taubi



  • Da ich grade auch mit VS rumspiele, wollte ich mal dein Code ungefähr übernehmen. Und bei mir funktioniert es... Hier mein Testcode:

    #include <windows.h>
    
    static void __cdecl DummyFunc(UINT a, UINT b, UINT c, UINT d);
    
    int WINAPI WinMain(
            HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            PSTR szCmdLine,
            int iCmdShow)
    {
        TCHAR szText[] = TEXT("Hallo !");
        TCHAR szCaption[] = TEXT("Meldung");
        UINT SPstart = 0;
        UINT Flag = MB_OK;
        UINT isStdCall = 0;
        TCHAR *pText = &szText[0];
        TCHAR *pCaption = &szCaption[0];
        UINT i = 0u;
        LPVOID pFunc = NULL;
        UINT testStdCall = 0u;
    
        for (i = 0u; i < 10; ++i)
        {
            testStdCall = (0u == (i % 2u));
    
            if (0u == testStdCall)
            {
                pFunc = DummyFunc;
            }
            else
            {
                pFunc = MessageBox;
            }
    
            __asm 
            { 
                mov SPstart, esp
    
                push Flag
                push pCaption
                push pText
                push 0
    
                call dword ptr pFunc
    
                cmp esp, SPstart
                je stdcall
                mov isStdCall, 0
                add esp, 16
                jmp end 
                stdcall:
                mov isStdCall, 1 
                end: 
            }
    
            if (0u == testStdCall)
            {
                if (0u != isStdCall)
                {
                    MessageBox(NULL, TEXT("Fehler !"), TEXT("Fehler!"), MB_OK);
                }
            }
            else
            {
                if (0u == isStdCall)
                {
                    MessageBox(NULL, TEXT("Fehler !"), TEXT("Fehler!"), MB_OK);
                }
            }
        }
    
        return 0;
    }
    
    static void __cdecl DummyFunc(UINT a, UINT b, UINT c, UINT d)
    {
        a = a;
        b = b;
        c = c;
        d = d;
    }
    

    Im Prinzip habe ich ja auch Pointer pText und pCaption, die auf dem Stack landen. Bei Dir ist wahrscheinlich ein anderes Problem, als das, was Du vermutest...



  • Hallo abc.w,

    danke für Deine schnelle Antwort. Ich kann den Vorschlag erst am Freitag testen. Wobei ich so richtige Unterschiede nicht feststellen konnte. Der Aufruf der Funktion ist etwas anders. Gibt es da Unterschiede zwischen Funktion und Funktionspointer. Ich glaube ja immer noch das das Problem an meinen Funktionsargumenten liegt. Meine erste Testfunktion war ohne Array's dort hat es funktioniert. Vielleicht kann mir ja jemand nochmal beschreiben ob es Unterschiede in Abhängigkeit vom Typ einer globalen C-Variablen gibt, wenn diese auf den Stack abgelegt werden soll.

    Gruß Taubi



  • vergleich doch auch ma, was der compiler aus nem reinen c-ausruf der dllfunc macht (im VS-debugger -> rechtsklick -> show dissassembly), un dann kopier dir den teil raus wo der die parameter aufgen stack legt



  • Taubi schrieb:

    Ich kann den Vorschlag erst am Freitag testen.

    Feierst Du jetzt schon Silvester? 😉 Bezüglich der Arrays musst Du aufpassen, man kann die nicht einfach so "pushen". Bezogen auf meinen Testcode muss man das so machen:

    __asm 
            { 
                mov SPstart, esp
    
                push Flag
                lea eax, szCaption
                push eax
                lea eax, szText
                push eax
                push 0
    
                call pFunc
    
                mov eax, 0
                cmp esp, SPstart
                sete al
                cmovne esp, SPstart
                mov isStdCall, eax
            }
    

    Also mit "lea" effektive Adresse holen, warum auch immer. Ich habe den Code noch ein wenig geändert und die ganzen Sprungbefehle rausgeschmissen.



  • So neues Jahr, neues Glück. Ich habe mich nun nochmal mit meinem Problem beschäftigt und habe jetzt folgende Lösung.

    void (*MyDLLFunction)(float *var1, int *var2, char *var3, char *var4, char *var5);
    
    MyDLLFunc = GetProcAddress(...);
    bool isStdCall;
    void *SPstart = NULL;
    float *var1 = Data;
    int *var2 = FailFlag;
    char *var3 = Infile;
    char *var4 = Outfile;
    char *var5 = Msg;
    
    __asm
    {
      mov SPstart, esp
      mov eax, dword ptr[var5]
      push eax
      mov eax, dword ptr[var4]
      push eax
      mov eax, dword ptr[var3]
      push eax
      mov eax, dword ptr[var2]
      push eax
      mov eax, dword ptr[var1]
      push eax
      call MyDLLFunc
      cmp esp, SPstart
      sete isStdCall 
      je end
      pop ebx
      pop ebx
      pop ebx
      pop ebx
      pop ebx
      end:
    }
    

    Danke nochmal an alle die mich bei der Lösungsfindung unterstützt haben. Wichtig bei VS inline Assembler ist, dass die C-Variablen in dem scope definiert sind, in dem sich auch der _asm-Block befindet. Das ist mir längere Zeit nicht aufgefallen. Ich hatte den _asm-Block in einer Memberfunktion einer Klasse definiert und dann auf Membervariablen zugegriffen. Das ließ sich auch alles fehlerfrei übersetzen nur im Assembler hatten die Variablen keine gültigen Adressen. Was mich dann längere Zeit verwundern ließ.

    Gruß Taubi


Anmelden zum Antworten