通过内联 x86 将双精度值传递给函数
无论如何,我都不是汇编方面的专业人士,并且在运行我的代码时收到以下错误:“运行时检查失败#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 方法编写的所有包装器,用于添加错误检查。
I am not a professional at assembly by any means and am receiving the following error when running my code: "Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call."
I am currently working on binding C-style functions to Python 3.2 using the CPython library and have run into an issue in my code with passing doubles. I have a single template function that is used to call the C function that is prototyped as such:
template <const char* MODULE, const char* FUNCTION>
static PyObject* ModuleFunction (PyObject* self, PyObject* param);
Currently my method works for passing integral types between Python and C/C++, but I'm having trouble with doubles. Maybe someone more well versed in x86 assembly can spot what I'm doing wrong. I've extracted all the code that does not involve doubles in my snippet:
__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:
}
Clarification on the following functions I used that may not be clear to everyone:
PyObject* Py_GrabElementFromTuple(PyObject* tuple, int index);
PyObject* Py_WrapDouble(double d);
double Py_ExtractDouble(PyObject* obj);
The above functions are all wrappers I wrote around CPython methods to add error checking.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
仅当采用
exractDouble
路径时,您的推送和弹出操作才会对称。如果您跳转到endLoop
,则推送次数会比弹出次数多两次。一般来说,您应该避免函数参数推送和实际函数调用之间的分支,除非您知道自己在做什么。另外,
fstp qword ptr [esp]
似乎是错误的,因为它覆盖了返回地址。您可能想在之前从 esp 中减去 8,当然在再次调用之后调整堆栈。Your pushes and pops are only symmetrical if the
exractDouble
path is taken. In case you jump toendLoop
you have two more pushes than pops. Generally you should avoid branches between function argument pushing and the actual function call, unless you know what you are doing.Additionally the
fstp qword ptr [esp]
seems wrong, because it overwrites the return address. You probably want to subtract 8 from esp before and of course adjust the stack after the call again.