0

私は決してアセンブリの専門家ではなく、コードを実行すると次のエラーが発生します。「ランタイムチェックの失敗#0-ESPの値が関数呼び出し全体で適切に保存されませんでした。」

私は現在、CPythonライブラリを使用してCスタイルの関数をPython 3.2にバインドする作業を行っていますが、コードでdoubleを渡す際に問題が発生しました。そのようにプロトタイプ化されたC関数を呼び出すために使用される単一のテンプレート関数があります。

template <const char* MODULE, const char* FUNCTION>
static PyObject* ModuleFunction (PyObject* self, PyObject* param);

現在、私のメソッドはPythonとC / C ++の間で整数型を渡すために機能しますが、doubleで問題が発生しています。たぶん、x86アセンブリに精通している人が、私が間違っていることに気付くことができます。スニペットにdoubleを含まないすべてのコードを抽出しました。

__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場合は、ポップより2回多くプッシュします。一般に、何をしているのかわからない限り、関数の引数のプッシュと実際の関数呼び出しの間の分岐は避けてください。

さらに、fstp qword ptr [esp]差出人住所が上書きされるため、は間違っているようです。おそらく、前にespから8を引き、もちろん、呼び出し後にスタックを再度調整する必要があります。

于 2011-05-13T22:38:48.657 に答える