0

I have a program with a function made only with inline assembly.

This function is used to call other functions we variable arguments (number and type).

All my program work very well in Debug mode but when I test it in release, I have this error :

SomeThing.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x0A4B2FFC).

Here is my assembly function :

__declspec( naked ) void Player_dummyFunction( dvrFunction* iFunc )
{
    __asm push ebp  
    __asm mov ebp,esp  
    __asm sub esp,0C0h  
    __asm push ebx  
    __asm push esi  
    __asm push edi  
    __asm lea edi,[ebp-0C0h]  
    __asm mov ecx,30h  
    __asm mov eax,0CCCCCCCCh  
    __asm rep stos dword ptr es:[edi]  

    /* Need the number of params. */
    __asm mov ecx, dword ptr [iFunc]            /* Use the calling convention of VC */
    __asm call dvrFunction::GetParamsNumber     /* this->m_ParamsData.size() */

    __asm mov edx, eax              /* Save the return value */

    __asm cmp edx, 0                /* Condition to know if the GL function has params (edx == 0) */
    __asm jz body                   /* Jump to the body label if the previous condition is true */

push_loop:
    /* Push the parameters in the reverse order on the stack */
    __asm mov ecx, dword ptr [iFunc]                /* Another use of the calling convention */
    __asm push edx
    __asm call dvrFunction::GetParamsAddress        /* this->m_ParamsData[i]->GetAddress() */

    __asm push [eax]                /* Push the dereferenced address (the value) on the stack */

    /* edx is automatically decremented by GetParamsAddress */
    __asm cmp edx, 0                /* Is edx == 0 ? */
    __asm jnz push_loop             /* If no, go back push_loop label */

body:
    __asm mov ecx, dword ptr [iFunc]                    /* Use the thiscall convention */
    __asm call dvrFunction::GetCName                    /* Call GetCName to have a const char* */

    __asm push eax                                      /* Push the name into the stack */
    __asm lea ecx, g_PlatBuiltin                        /* Use another convention for the structs */

    __asm call [ecx]g_PlatBuiltin.wglGetProcAddress     /* Call the real wglGetProcAddress to have the pointer to the GL function */
    __asm mov ecx, eax                                  /* Save the result -> TODO Is this operation needed ? */

    __asm call ecx                                      /* Call the original open GL function */

    __asm pop edi  
    __asm pop esi  
    __asm pop ebx  
    __asm add esp,0C0h  
    __asm cmp ebp,esp  
    //__asm call __RTC_CheckEsp (0125114Fh)  
    __asm mov esp,ebp  
    __asm pop ebp

    __asm ret                                           /* Call the ret asm command */
}
4

3 回答 3

1

这不是一个真正的答案,但注释中的代码变得非常混乱,汇编代码更糟糕,因为它比 C/C++ 更多地依赖换行符来格式化。

__asm lea edi,[ebp-0C0h]  
__asm mov ecx,30h  
__asm mov eax,0CCCCCCCCh  
__asm rep stos dword ptr es:[edi]  

这是“调试模式”代码,你真的不应该在发布模式下这样做。事实上,我很确定,您的功能根本不需要大多数 Epilog 和 prolog 代码——它只是“调试”的东西。

现在可能是一个答案:我感觉崩溃是由于GetParamsNumber在非调试模式下返回的数字比在调试模式下返回的数字大。我对此完全不确定,这对我来说是最有意义的。或者可能GetParamsNumber返回一些负面的东西?

您的代码也依赖于edx不被更改GetParamsAddress,这可能不是真的?特别是,它可能会根据优化模式而改变。

于 2013-04-19T10:01:19.280 回答
0

尝试在版本中添加 /Oy-

并检查其他优化选项:msdn

于 2013-04-19T09:47:15.173 回答
0

我的猜测是在 ret 指令之后流水线会运行到一些代码中。我看到您的堆栈非常细致地恢复,超出了正常需求。(事实上​​,如果其中一些函数破坏了 ebp 怎么办?评论 __asm mov esp,ebp ?)这是我认为应该尝试各种组合的方法:

  • nop在决赛后增加 16秒ret
  • 放弃那个esp恢复。// __asm mov esp,ebp
  • 用降低堆栈指针包围代码,这样如果一些代码弹出太多,顶部就不会被破坏:(尤其是保存在这里)sub esp,1000,代码在这里,mov esp,ebp(假设你有堆栈恢复到位)。
  • 移动堆栈恢复内容,稍后/inside/您的寄存器恢复内容。如果堆栈确实在您的代码中损坏,您的恢复代码将不会像现在一样保存您的 esi、edi 和 ebx 寄存器。__asm push ebp
    __asm mov ebp,esp
    __asm mov esp,ebp
    __asm pop ebp
  • 注释掉你的函数调用,看看哪个函数破坏了它,然后逐渐找出如何恢复以前的状态。
于 2013-04-19T10:03:29.247 回答