我有一个程序,其功能仅使用内联汇编。
此函数用于调用我们变量参数(数字和类型)的其他函数。
我的所有程序在调试模式下工作得很好但是当我在发布时测试它时,我有这个错误:
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 */
}
答案 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寄存器。