仅在发布时内联汇编错误

时间:2013-04-19 09:20:36

标签: c++ assembly stack-overflow inline-assembly

我有一个程序,其功能仅使用内联汇编。

此函数用于调用我们变量参数(数字和类型)的其他函数。

我的所有程序在调试模式下工作得很好但是当我在发布时测试它时,我有这个错误:

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

这是我的汇编函数:

__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 */
}

3 个答案:

答案 0 :(得分: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更改,这可能不是真的?特别是,它可以基于优化模式进行更改。

答案 1 :(得分:0)

尝试在发布中添加/ Oy-

并查看其他优化选项:msdn

答案 2 :(得分:0)

我的猜测是,在ret指令之后,流水线会运行一些代码。我看到你的堆栈已经非常精心地恢复,超出了正常需求。 (事实上​​,如果其中一些功能破坏ebp怎么办?注释__asm mov esp,ebp?)以下是我认为应该尝试各种组合:

  • 在最终nop之后添加16 ret
  • 删除esp恢复。 // __asm mov esp,ebp
  • 通过降低堆栈指针来包围代码,这样如果某些代码弹出太多,则顶部不会被破坏:(特此保存在这里)sub esp,1000,代码在这里,mov esp,ebp(假设你已经进行了堆栈恢复。)
  • 移动堆栈恢复内容,__asm push ebp
    __asm mov ebp,esp
    ,稍后__asm mov esp,ebp
    __asm pop ebp
    / inside /您的注册恢复内容。如果代码中的堆栈确实已损坏,则恢复代码将不会像现在这样保存您的esi,edi和ebx寄存器。
  • 注释掉你的函数调用以查看哪个函数破坏了它,然后逐步找出如何恢复以前的状态。