допустим есть функция int __cdecl func_c(int a, int b, int c) { return a+b+c; // это для примера } а я хочу сделать функцию типа int __stdcall InvokeFunc(void* func_c, int a, int b, int c) или в общем случае int __stdcall InvokeFunc(void* func_c, int число параметров, [параметры]) которая не трогая стек с параметрами просто передает управление на func_c InvokeFunc proc stdcall public, funcptrWORD pop ecx ; save return address pop edx ; Get function pointer push ecx ; Restore return address jmp edx ; Transfer control to the function pointer InvokeFunc endp объясните почему портится ESP (на [число параметров]*4) и как это поправить?
mofer cdecl не чистит стек. Можно сделать так: Код (Text): int __cdecl func_c(void* unused_param, int a, int b, int c) { return a+b+c; // это для примера } InvokeFunc proc stdcall public, funcptr:DWORD pop ecx pop edx push ecx call edx pop ecx pop edx shl edx,2 add esp,edx jmp ecx InvokeFunc endp Хотя проще сделать InvokeFunc cdecl.
> Quantum > int __cdecl func_c(void* unused_param, int a, int b, int c) мне нельзя портить func_c (это какая нибудь экспортируемая в длл функция) > Хотя проще сделать InvokeFunc cdecl. это нужно чтобы вызывать __cdecl функции из C# (а там по умолчанию все в __sdcall) > Jupiter я не понял про что ты... ------------------------------------------ int __cdecl func_c(int a, int b, int c) int __stdcall func_s(int a, int b, int c) func_c(1,2,3): push 3 push 2 push 1 call func_c add esp, 12 func_s(1,2,3): push 3 push 2 push 1 call func_s Я правильно понимаю вызов эти двух функций отличает только на сдвиг esp? ----- InvokeFunc proc stdcall public, funcptrWORD pop ecx ; return address pop edx ; Get function pointer call edx ; передать управление с возвратом add esp, 12 ; сдвинуть указатель InvokeFunc endp Это правильно для моего примера?
mofer Тогда eip можно сохранить в глобальную переменную: Код (Text): InvokeFunc proc stdcall public, funcptr:DWORD pop DWORD PTR [save_eip] pop edx call edx pop edx shl edx,2 add esp,edx jmp DWORD PTR [save_eip] InvokeFunc endp Да, cdecl не чистит после себя стек и это приходится делать тому, кто вызывает её, а stdcall всё делает сама!
Или добавлять в конец зарезервированный параметр dwReserved, в который и записывать адрес возврата A вообще-то универсальная InvokeFunc с косвенным call, да еще и с jmp вместо ret это плохо с точки зрения быстродействия
mofer Прежде всего следует определиться с точным прототипом этой ф-ции. Если имеется в виду Код (Text): int __stdcall InvokeFunc(void* func_c, int cParam, ...) то все эти извращения не нужны: __stdcall с переменным кол. арг. - это то же самое (по части стека), что и __cdecl.
green Мне не нужен точный прототип фукции... я просто использую то что по стэку __sdcall и __cdecl одинаковы. Я делаю длл c описанно фукцией а потом могу вызывать любую функцию __cdecl из C# где все функции __stdcall. для примера, есть функция: int __cdecl DLLFUNC_C(int a1, int a2, ... int an) в библиотеке a.dll я делаю классик чтобы динамически ее вызывать Код (Text): class Class1{ [DllImport("kernel32")] public extern static int LoadLibrary(string lpLibFileName); [DllImport("kernel32")] public extern static bool FreeLibrary(int hLibModule); [DllImport("kernel32", CharSet=CharSet.Ansi)] public extern static int GetProcAddress(int hModule, string lpProcName); [DllImport("Invoke")] public extern static int InvokeFunc(int funcptr, int a1, int a2, ... int an, число параметров); static void Main(string[] args) { int hmod=LoadLibrary("a.dll"); int funcaddr=GetProcAddress(hmod, "DLLFUNC_C"); int result=InvokeFunc(funcaddr, a1, a2, ... an, n); FreeLibrary(hmod); } } прототип я определяю в зависимости от используемой функции и вызываю ее динамически как native фунцию. InvokeFunc(funcaddr, a1, a2, ... an, n); фукция передает управление на funcaddr которая вычитывает из стека все параметры затем считывает последний параметр и сдвигает esp на нужное число. всем спасибо за коментарии!
mofer Тогда так, по идее, должно работать: Код (Text): ; int "__stdcall" InvokeFunc(void* func_c, int число параметров, [параметры]) InvokeFunc proc mov eax, [esp+8] xchg eax, [esp+4] add esp, 0Ch call eax mov eax, [esp-8] mov ecx, [esp-0Ch] shl eax, 2 add esp, eax jmp ecx InvokeFunc endp