通过内联x86将double传递给函数

时间:2011-05-13 22:12:18

标签: x86 inline-assembly cpython fpu

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

1 个答案:

答案 0 :(得分:0)

如果采用exractDouble路径,您的推送和弹出只是对称的。如果你跳到endLoop,你还有两次推送而不是流行音乐。通常你应该避免在函数参数推送和实际函数调用之间的分支,除非你知道你在做什么。

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