windows - Variable argumenter i \_stdcall, C ++/Inline ASM

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg er i en situation, hvor jeg skal mocke en \_stdcall-funktion ved hjælp af C ++ og inline ASM, men som bruger et variabelt antal argumenter. Normalt ville det ikke vide, hvor mange argumenter der skal pope fra stakken, når den vender tilbage til dens forælder, så ville det ikke virke, men jeg håber at fortælle det via en global variabel, hvor mange parametre det skal have, og så få det til at pope dem væk.


Er det faktisk muligt? Hvis ja, kan nogen starte mig i den rigtige retning? Jeg er specielt fast med epilog-koden, jeg ville have brug for.


Mit mål er at lave en funktion, der kan bruges som tilbagekald for enhver funktion, der kræver en (som EnumWindows), så længe brugeren fortæller det i kørselstid, hvor længe args-listen skal være. Ideen er, at den kan integrere med nogle kode andre steder, så det kører i princippet hver gang tilbagekaldelsen kaldes og giver et link til et sted, hvor de variable, der blev returneret, kan læses og ses af brugeren.


Giver det mening?

Bedste reference


Du kan gøre noget som følger (hacked up kode):


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

Andre referencer 1


Det giver ikke mening. \_\_stdcall tillader ikke variadiske parametre, da den samlede størrelse af alle parametre er inddelt i funktionsnavnet (fra msdn): [8]



  Navn-dekoration konvention

  
  En understregning (\_) er præfikset til navnet. Navnet efterfølges af signaturet (@) efterfulgt af antallet af bytes (i decimaltal) i argumentlisten . Derfor er funktionen erklæret som int func( int a, double b ) dekoreret som følger: \_func@12



Dette citat fortæller dig, hvordan variadiske \_\_stdcall funktioner er implementeret:



  \_\_Stdcall-kaldkonventionen bruges til at ringe til Win32 API-funktioner. Callee renser stakken, så kompilatoren gør varargfunktioner \_\_cdecl . Funktioner, der bruger denne kaldende konvention, kræver en funktion prototype.



(vægt min)

Så der er ingen \_\_stdcall funktioner med variadiske parametre, de bliver stille ændret til \_\_cdecl. :)