Переменные аргументы в _stdcall, C ++ / Inline ASM - PullRequest
0 голосов
/ 10 апреля 2011

Я нахожусь в ситуации, когда мне приходится макетировать функцию _stdcall с использованием C ++ и встроенного ASM, но которая использует переменное число аргументов. Обычно он не знает, сколько аргументов нужно извлечь из стека, когда он возвращает управление своему родителю, поэтому не сработает, но я надеюсь сообщить ему через глобальную переменную, какое количество параметров должно быть, а затем получить его чтобы вытащить их вот так.

Это действительно возможно? Если так, может ли кто-нибудь начать меня в правильном направлении? Я специально застрял с эпилог-кодом, который мне понадобится.

Моя цель - создать функцию, которая может использоваться в качестве обратного вызова для любой функции, для которой она требуется (например, EnumWindows), при условии, что пользователь сообщает ей во время выполнения, насколько длинным должен быть список аргументов. Идея состоит в том, чтобы он интегрировался с некоторым кодом в другом месте, поэтому он в основном запускает триггер каждый раз, когда вызывается обратный вызов, и предоставляет ссылку на место, где возвращаемые переменные могут быть прочитаны и просмотрены пользователем.

Имеет ли это смысл?

Ответы [ 2 ]

4 голосов
/ 10 апреля 2011

Не имеет смысла. __stdcall не допускает переменных параметров, так как общий размер всех параметров оформляется в имя функции ( из msdn ):

Наименование-декорация

Подчеркивание (_) начинается с префикса имени. За именем следует знак (@) , за которым следует число байтов (в десятичной дроби) в списке аргументов . Поэтому функция, объявленная как int func( int a, double b ), оформлена следующим образом: _func@12

В этой цитате рассказывается, как реализованы различные __stdcall функции:

Соглашение о вызовах __stdcall используется для вызова функций Win32 API. Вызываемый объект очищает стек, поэтому компилятор выполняет функции vararg __cdecl . Для функций, использующих это соглашение о вызовах, требуется прототип функции.

(акцент мой)
Итак, __stdcall функций с переменными параметрами нет, они молча меняются на __cdecl. :)

0 голосов
/ 12 апреля 2011

Вы можете сделать что-то вроде следующего (взломанный код):

static int NumberOfParameters = 0;

__declspec(naked) void GenericCallback()
{
    // prologue
    __asm push ebp
    __asm mov ebp, esp

    // TODO: do something with parameters on stack

    // manual stack unwinding for 2 parameters
    // obviously you would adjust for the appropriate number of parameters
    // (e.g. NumberOfParameters) instead of hard-coding it for 2
    // fixup frame pointer
    __asm mov eax, [ebp + 0]
    __asm mov [ebp + 8], eax // NumberOfParameters * 4 (assuming dword-sized parameters)
    // fixup return address
    __asm mov eax, [ebp + 4]
    __asm mov [ebp + 12], eax // (NumberOfParameters + 1) * 4
    // return TRUE
    __asm mov eax, 1
    // epilogue
    __asm mov esp, ebp
    __asm pop ebp
    // fixup stack pointer
    __asm add esp, 8 // NumberOfParameters * 4
    __asm ret 0
}

int main(int argc, _TCHAR* argv[])
{
    NumberOfParameters = 2;
    EnumWindows((WNDENUMPROC)GenericCallback, NULL);
    return 0;
}
...