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 eaxcall 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 DankTaubi
-
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