0

我无论如何都不是组装专业人士,并且在运行我的代码时收到以下错误:“运行时检查失败 #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 方法编写的用于添加错误检查的包装器。

4

1 回答 1

0

exractDouble仅当采用路径时,您的推送和弹出是对称的。万一你跳到endLoop你有两个比弹出多推。通常你应该避免函数参数推送和实际函数调用之间的分支,除非你知道你在做什么。

此外,这fstp qword ptr [esp]似乎是错误的,因为它会覆盖返回地址。您可能想在之前从 esp 中减去 8,当然在再次调用之后调整堆栈。

于 2011-05-13T22:38:48.657 回答