C++ 仅在版本中出现内联程序集错误
我有一个只有内联汇编才能实现的程序 此函数用于调用我们使用变量参数(数字和类型)的其他函数 我的所有程序在调试模式下都工作得很好,但当我在发行版中测试它时,出现以下错误:C++ 仅在版本中出现内联程序集错误,c++,assembly,stack-overflow,inline-assembly,C++,Assembly,Stack Overflow,Inline Assembly,我有一个只有内联汇编才能实现的程序 此函数用于调用我们使用变量参数(数字和类型)的其他函数 我的所有程序在调试模式下都工作得很好,但当我在发行版中测试它时,出现以下错误: SomeThing.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x0A4B2FFC). 下面是我的汇编函数: __declspec( naked ) void Player_dummyFunction( dvrFunction* iFunc ) {
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 */
}
尝试在发行版中添加/Oy-
检查其他优化选项:这不是一个真正的答案,但是注释中的代码变得非常混乱,汇编代码更糟糕,因为它比C/C++更依赖换行符进行格式化
__asm lea edi,[ebp-0C0h]
__asm mov ecx,30h
__asm mov eax,0CCCCCCCCh
__asm rep stos dword ptr es:[edi]
这是“调试模式”代码,您真的不应该在发布模式下这样做。我很确定,事实上,大部分的epilog和prolog代码根本不需要你的功能——它只是“调试”的东西
现在有一些可能是答案:
我感觉崩溃是由getparamsumber
在非调试模式下返回的数字大于在调试模式下返回的数字引起的。我绝对不确定,这对我来说才是最有意义的。或者,getParamsMember
是否返回负数
您的代码还依赖于
edx
未被GetParamsAddress
更改,这可能不是真的?特别是,它可能会根据优化模式而改变 我的猜测是,在ret指令之后,管道将运行到某些代码中。我看到您已经非常仔细地恢复了堆栈,高于正常需要。(事实上,如果这些函数中的某些函数破坏了ebp呢?注释?uu asm mov esp,ebp?)我认为应该以各种组合尝试以下内容:
- 在最后的
之后添加16个ret
snop
- 删除
恢复<代码>/\u asm mov esp,ebpesp
- 降低堆栈指针以包围代码,这样,如果某些代码弹出过多,顶部不会损坏:(esp在此保存)
,code here,sub esp,1000
(假设堆栈已恢复到位)mov esp,ebp
- 移动堆栈还原内容,
,以后的\u asm push ebp
__asm mov ebp,esp
/在/您的注册表中还原内容。若堆栈确实在代码中损坏,那个么恢复代码将不会像现在那个样保存esi、edi和ebx寄存器\uu asm mov esp,ebp
__asm pop ebp - 注释掉你的函数调用,看看哪个函数破坏了它,然后逐步找出如何恢复以前的状态
push[eax]
之后的那一行。您可以尝试逐行调试(使用/O1)以查看此时eax中的内容。。试着找出它的值是否正确。(调试汇编总是很有趣的--)我很确定情况并非如此。x86是一致的体系结构,这意味着依赖于其他指令的指令将暂停,直到其依赖关系完成。您可以编写任何您喜欢的内容,以任何顺序在x86中生成正确的结果,并且它将实现您期望的功能[根据处理器勘误表,但我100%确定这不是处理器勘误表]。我越是看它,我就觉得它是“被其他东西使用后再使用寄存器”。这是正确的答案,我刚刚看到我的edx在调用GetParamsAddress后是假的。我通过在函数调用后添加pop-edx解决了这个问题。我知道epilog和prolog是不需要的,但实际上我添加了它,因为我正在探索能够解决这个问题的各种可能性:-)但感谢您的帮助。为了提高效率,您可以尝试使用“被调用方保存”的寄存器,如EDI或ESI。[但是,您确实需要在代码开始时推送该寄存器-但它确实将代码保存在循环中]谢谢您的建议。我会的。