Passer un double à une fonction via x86 en ligne
-
13-11-2019 - |
Question
Je ne suis en aucun cas un professionnel de l'assemblage et je reçois l'erreur suivante lors de l'exécution de mon code :"Échec du contrôle d'exécution n°0 - La valeur de l'ESP n'a pas été correctement enregistrée lors d'un appel de fonction."
Je travaille actuellement sur la liaison des fonctions de style C à Python 3.2 à l'aide de la bibliothèque CPython et j'ai rencontré un problème dans mon code avec le passage de doubles.J'ai une seule fonction de modèle utilisée pour appeler la fonction C qui est prototypée comme telle :
template <const char* MODULE, const char* FUNCTION>
static PyObject* ModuleFunction (PyObject* self, PyObject* param);
Actuellement, ma méthode fonctionne pour transmettre des types intégraux entre Python et C/C++, mais j'ai des problèmes avec les doubles.Peut-être que quelqu'un de plus familiarisé avec l'assemblage x86 pourra repérer ce que je fais de mal.J'ai extrait tout le code qui n'implique pas de doubles dans mon extrait :
__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 sur les fonctions suivantes que j'ai utilisées et qui peuvent ne pas être claires pour tout le monde :
PyObject* Py_GrabElementFromTuple(PyObject* tuple, int index);
PyObject* Py_WrapDouble(double d);
double Py_ExtractDouble(PyObject* obj);
Les fonctions ci-dessus sont toutes des wrappers que j'ai écrits autour des méthodes CPython pour ajouter une vérification des erreurs.
La solution
Vos poussées et pops ne sont symétriques que si le exractDouble
le chemin est emprunté.Au cas où vous sauteriez vers endLoop
vous avez deux poussées de plus que des pops.En règle générale, vous devez éviter les branches entre la poussée des arguments de fonction et l'appel de fonction réel, à moins que vous ne sachiez ce que vous faites.
De plus le fstp qword ptr [esp]
semble faux, car il écrase l'adresse de retour.Vous souhaitez probablement soustraire 8 de esp avant et bien sûr ajuster à nouveau la pile après l'appel.