简体   繁体   中英

Variable arguments in _stdcall, C++ / Inline ASM

I'm in a situation where I have to mock up a _stdcall function using C++ and inline ASM, but which uses a variable number of arguments. Normally it wouldn't know how many arguments to pop from the stack when it returns control to its parent, so wouldn't work, but I'm hoping to tell it via a global variable how many params it should have and then get it to pop them off like that.

Is that actually possible? If so, can someone start me off in the right direction? I'm specifically stuck with the epilog code I would need.

My objective is to make a function which can be used as a callback for any function that requires one (like EnumWindows), so long as the user tells it at runtime how long the args list has to be. The idea is for it to integrate with some code elsewhere so it basically runs a trigger each time the callback is called and provides a link to a place where the variables that were returned can be read and viewed by the user.

Does that make sense?

Doesn't make sense. __stdcall doesn't allow variadic parameters, as the total size of all parameters is decorated into the function name ( from msdn ):

Name-decoration convention

An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list . Therefore, the function declared as int func( int a, double b ) is decorated as follows: _func@12

This quote tells you how variadic __stdcall functions are implemented:

The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl . Functions that use this calling convention require a function prototype.

(emphasis mine)
So, there are no __stdcall functions with variadic parameters, they silently get changed to __cdecl . :)

You can do something like the following (hacked up code):

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM