2010-02-22 2 views
8

Donc, je voudrais pouvoir appeler des fonctions à partir d'une DLL C++. Pour certaines raisons, je voudrais les appeler à partir d'un bloc __asm ​​dans mon code C++. Ma question est la suivante: je sais que avant d'appeler la fonction, je dois pousser ses arguments sur la pile dans l'ordre spécifié en appelant convention.However, puis-je faire simplement de la fonction quelque chose comme ceci:Comment puis-je passer des arguments aux fonctions C++ lorsque je les appelle à partir de l'assemblage en ligne

int a=5; 
double b = 5.0; 
__asm{ 
     push b 
     push a 
     call functionAddress 
} 

Ce qui m'inquiète, c'est que je me souviens que la taille standard d'un assemblage est de 2 octets, alors que la taille d'un int en C++ est habituellement de 4 octets, et de 8 octets pour un double.So, dans l'exemple ci-dessus, suis-je? poussant vraiment la pleine valeur de chaque variable, ou juste le premier couple d'octets? Si le code ci-dessus n'est pas correct, quelle serait la bonne façon de le faire? De plus, si la fonction que nous appelons renvoie un double, où cette valeur est-elle stockée? Je suppose qu'il ne peut pas être dans un registre, car il ne peut stocker que 32 bits (4 octets). Toute aide avec ce désordre serait grandement appréciée :)

+2

Que s'est-il passé lorsque vous l'avez essayé? – Seth

+0

J'ai un problème avec les doubles: je me suis fait une fonction de test dans la dll qui prend un double argument et renvoie 1 si l'entrée est plus grande que 5.0.Le truc c'est que j'ai essayé d'appeler la fonction plusieurs fois avec l'argument 7.45454 et la valeur de retour n'est pas toujours la même. –

Répondre

13

Pour pousser les valeurs de 8 octets tels que doubles, vous ne serez pas en mesure d'utiliser une instruction PUSH régulière. Et vous ne poussez pas non plus de paramètres à virgule flottante (ou doubles) sur la pile à virgule flottante. Vous devez mettre ces paramètres de graisse sur la pile 'à la main'. Par exemple, pour envoyer π en tant que paramètre à une fonction f:

__asm { 
    FLDPI     // load pi onto FP stack 
    SUB ESP,8    // make room for double on processor stack 
    FSTP QWORD PTR [ESP]  // store pi in proc stack slot (and pop from FP stack) 
    CALL f 
    ADD ESP,8    // clean up stack (assuming f is _cdecl) 
    } 
1

En général, vous seriez pousser la taille réelle de l'ordinateur mot. Cela varie en fonction de la puce, mais sur un Intel 32 bits serait 4 octets, et sur un Intel 64, serait de 8 (en fonction du compilateur - Visual Studio ne supporte toujours que l'assemblage IA32 - donc 4 octets).

La meilleure réponse est de regarder la documentation de votre compilateur spécifique.

4

L'architecture x86 32 bits remplit automatiquement les valeurs envoyées sur la pile à 32 bits.

Il y a quelque chose que vous devez garder à l'esprit. Si la fonction que vous appelez utilise la convention d'appel __cdecl, vous devez "pop" ce que vous avez poussé après. Cependant, pour les fonctions __stdcall, vous ne devez pas le faire.

extern "C" int __cdecl function1(int, double); 
extern "C" double __stdcall function2(char, char*); 

int a = 5; 
double b = 5.0; 
int retval1; 
char c = '5'; 
char *d = "Hello"; 
double retval2; 

__asm { 
    push b 
    push a 
    call function1 
    add esp, 4*2 // "pop" what we pushed 
    mov retval1, eax 
    push d 
    push c 
    call function2 
    mov retval2, eax 
} 
+2

Pour plus de tranquillité d'esprit, une fois que vous avez compris ce qu'il devrait être, faites l'appel équivalent à partir de C++, compilez avec les optimisations désactivées et regardez la sortie de l'assemblage. Cela devrait correspondre à peu près à ce que vous faites. –

+1

Mais alors, comment pousseriez-vous un double? En C++, il est supposé être de 8 octets, n'est-ce pas? –

Questions connexes