سؤال

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.

هل كانت مفيدة؟

المحلول

Your pushes and pops are only symmetrical if the exractDouble path is taken. In case you jump to endLoop 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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top