我在任何方面都不是专业人士,并且在运行我的代码时收到以下错误:“运行时检查失败#0 - ESP的值未在函数调用中正确保存。”
我目前正在使用CPython库将C风格的函数绑定到Python 3.2,并且在我的代码中遇到了传递双精度的问题。我有一个模板函数,用于调用原型的C函数:
template <const char* MODULE, const char* FUNCTION>
static PyObject* ModuleFunction (PyObject* self, PyObject* param);
目前我的方法适用于在Python和C / C ++之间传递整数类型,但我遇到双打问题。也许更熟悉x86汇编的人可以发现我做错了什么。我在我的代码段中提取了所有不涉及双打的代码:
__asm
{
mov ecx, num_params
mov ebx, 0
cmp ebx, ecx
je functionCall
extractParameters:
mov ebx, ecx
dec ebx
push ecx // save ecx
push ebx
push param
call Py_GrabElementFromTuple
pop edx // I know I could modify esp, but this made it more readable to me
pop edx
push eax // push the returned PyObject* onto the stack
mov edx, 0
mov ecx, dword ptr [paramTypes]
mov dl, byte ptr [ecx+ebx]
cmp decimal, edx
je extractDouble
jmp endLoop
extractDouble:
call Py_ExtractDouble
pop ebx
pop ecx
fstp qword ptr [esp]
jmp endLoop
endLoop:
loop extractParameters
functionCall:
call func
mov ecx, dword ptr [stacksize]
add esp, ecx
mov edx, returnType
cmp decimal, edx
je wrapDouble
jmp done
wrapDouble:
fstp qword ptr [esp]
call Py_WrapDouble
mov returnObj, eax
jmp done
done:
}
澄清我使用的以下功能可能并不是每个人都清楚:
PyObject* Py_GrabElementFromTuple(PyObject* tuple, int index);
PyObject* Py_WrapDouble(double d);
double Py_ExtractDouble(PyObject* obj);
上面的函数都是我在CPython方法中编写的包装器,用于添加错误检查。
答案 0 :(得分:0)
如果采用exractDouble
路径,您的推送和弹出只是对称的。如果你跳到endLoop
,你还有两次推送而不是流行音乐。通常你应该避免在函数参数推送和实际函数调用之间的分支,除非你知道你在做什么。
此外fstp qword ptr [esp]
似乎有误,因为它会覆盖返回地址。您可能希望之前从esp中减去8,当然再次调用后再调整堆栈。