Escrever funções nuas com código de prólogo e epilog personalizado no Visual Studio

Estou escrevendo algum código de plug-in em uma dll chamada por um host sobre o qual não tenho control

O host assume que os plugins são exportados como funções __stdcall. O host recebe o nome da função e os detalhes dos argumentos que espera e cria uma chamada dinamicamente para ele via LoadLibrary, GetProcAddress e manualmente pressionando os argumentos na pilh

ormalmente, as DLLs de plug-in expõem uma interface constante. Meu plug-in expõe uma interface configurada no tempo de carregamento da DLL. Para isso, meu plug-in expõe um conjunto de pontos de entrada padrão definidos no momento em que a dll é compilada e os aloca conforme necessário para a funcionalidade interna que está sendo expost

Cada uma das funções internas pode receber argumentos diferentes, mas isso é comunicado ao host junto com o nome do ponto de entrada físico. Todos os meus pontos de entrada da dll física são definidos para receber um único ponteiro nulo * e eu organizo os parâmetros subsequentes da pilha, trabalhando com as compensações do primeiro argumento e a lista de argumentos conhecidos que foi comunicada ao hos

O host pode chamar com êxito as funções no meu plug-in com os argumentos corretos e tudo funciona bem ... No entanto, eu sei que a) minhas funções não estão limpando a pilha como deveriam, como deveriam definido como funções __stdcall que usam um ponteiro de 4 bytes e, portanto, sempre fazem um 'ret 4' no final, mesmo que o chamador tenha empurrado mais argumentos para a pilha. eb) não consigo lidar com funções que não recebem argumentos, pois os ret 4 reterão 4 bytes demais da pilha no meu retorn

Tendo traçado fora do meu plugin no código de chamada do host, posso ver que, na verdade, a) não é grande coisa; o host perde um pouco de espaço na pilha até retornar da chamada de despacho; nesse momento, limpa seu quadro de pilha, o que limpa meu lixo; Contudo..

Eu posso resolver b) mudando para __cdecl e não limpando nada. Suponho que posso resolver a) alternando para funções simples e escrevendo meu próprio código genérico de limpeza de argument

Como eu sei a quantidade de espaço de argumento usada pela função que acabamos de chamar, esperava que fosse tão simples quanto:

extern "C" __declspec(naked) __declspec(dllexport) void  * __stdcall EntryPoint(void *pArg1)
{                                                                                                        
   size_t argumentSpaceUsed;
   {
      void *pX = RealEntryPoint(
         reinterpret_cast<ULONG_PTR>(&pArg1), 
         argumentSpaceUsed);

      __asm
      {
         mov eax, dword ptr pX
      }
   }
   __asm
   {
      ret argumentSpaceUsed
   }
}

Mas isso não funciona como ret precisa de uma constante de tempo de compilação ... Alguma sugestão?

ATUALIZADA

Graças às sugestões de Rob Kennedy, cheguei a isso, que parece funcionar ...

extern "C" __declspec(naked) __declspec(dllexport) void  * __stdcall EntryPoint(void *pArg1)
{      
   __asm {                                                                                                        
      push ebp          // Set up our stack frame            
      mov ebp, esp  
      mov eax, 0x0      // Space for called func to return arg space used, init to 0            
      push eax          // Set up stack for call to real Entry point
      push esp
      lea eax, pArg1                
      push eax                      
      call RealEntryPoint   // result is left in eax, we leave it there for our caller....         
      pop ecx 
      mov esp,ebp       // remove our stack frame
      pop ebp  
      pop edx           // return address off
      add esp, ecx      // remove 'x' bytes of caller args
      push edx          // return address back on                   
      ret                        
   }
}

Isso parece certo?

questionAnswers(1)

yourAnswerToTheQuestion