Ecrire un programme C utilisant des fonctions faites en assembleurs...

Ecrire un programme C utilisant des fonctions faites en assembleurs... - C++ - Programmation

Marsh Posté le 01-12-2002 à 01:51:53    

Voilà j'ai envie de faire un programe C qui utiliserait des fonction que j'aurai ecrit et compilé avec un assembleur séparer (MASM par exemple). Le problème c que je vois pas comment faire  au nivo des noms des procédures.
 
En gros j'ai envie de faire un truc dans ce gout là:
 
Programme en C:
 

Code :
  1. extern f(int, int);
  2. int main()
  3. {
  4. int a,b,c;
  5. ...
  6. a=f(b,c);
  7. ...
  8. }


 
Programme en asm:
 

Code :
  1. f PUBLIC
  2. code SEGMENT PUBLIC
  3. f PROC
  4.   push ebp
  5.   mov ebp,esp
  6.   mov eax,[ebp+4]
  7.   mov ebx,[ebp+6]
  8.   ...
  9.   pop ebp
  10. f ENDP
  11. code ENDS
  12.   END


 
Mais ça, ça marche pas j'ai une erreur au nivo de l'édition de lien. Ca me dit que f est introuvable :(  
 
Donc si quelqu'un sait comment faire ca ca m'aiderait pas mal.
 
NB: me dite pas d'utiliser l'assembleur inline c pas possible pour des raison de portabilité entre autre :)


Message édité par sombresonge le 01-12-2002 à 01:54:40
Reply

Marsh Posté le 01-12-2002 à 01:51:53   

Reply

Marsh Posté le 01-12-2002 à 02:07:52    

pour ce que je vais te décrire, je me base sur Watcom C/C++ à l'époque ou je codais en asm sous dos avec un dos-extender (dos4gw/pmodew):
étant donné que c'était du mode protégé, l'idée reste valable.
 
alors l'idéal:
 
jouer avec les #pragma et autres __fastcall pour que tes fonctions "extern" ayent leurs paramètres de passés par les registre et non par la pile.
 
les fonctions cotés asm doivent être déclarés de la manière suivante, dans le segment TEXT:
 
_TEXT SEGMENT DWORD PUBLIC 'CODE' ; déclaration du segment de code
PUBLIC FunctionAsm_ ; FunctionAsm_ sera "exporté" (nom de symbole conservé dans le .obj)
 
FunctionAsm_ PROC NEAR  ; déclaration de la fonction  
 
             ...
             ...
 
FunctionAsm_ ENDP
 
 
_TEXT ENDS ; fin du segment de code
 
 
le "_" semble être relativement standard aux compilateurs C.
 
attention: si tu link avec du c++, la déclaration de la fonction sera alors:
 
extern "C" FunctionAsm(int....);
 
ce qui était génial avec le watcom, c'est que tu pouvais forcer les paramètres dans chaque registre avec un truc style:
 
extern int yopla(int a, int b);
#pragma aux yopla parm [ecx] [esi] value [edx];
le int retourné se retrouvant dans edx, a dans ecx et b dans esi.
 
 
 

Reply

Marsh Posté le 01-12-2002 à 02:09:03    

je pense qu'il manque peut être le "_" au nom de fonction f.
 
à la limite fait une fonction à la con en C, dump le code asm et observe les conventions de nommage...

Reply

Marsh Posté le 01-12-2002 à 02:28:14    

Bon ca marche presque :D (le linkage est passé) manque plus qu'à trouver comment les paramettres sont passé et retrouver :pt1cable:  
 
Dans le code en ASM j'ai fait comme t'as dit sauf qu'il fallait mettre le _ devant le nom
Dans le code c fallait préciser en en-tete extern "C" f(int...)
 
Parceque comme je compilais mes fichier C sous visual ce con me les compilait comme si ct du C++ donc ca marchait pas donc fallait effectivement passer le "C" :pfff:

Reply

Marsh Posté le 01-12-2002 à 03:42:19    

Bon j'ai compris comment paser des paramettre de mon programme C vers mon code ASM.
En fait si une fonction admet comme paramettre:
f(int A, int B, int C)
le programe empile dans le stack
 
C puis B puis A puis EIP
 
donc pour recup les param dans le sous prog suffit de faire:
 

Code :
  1. push EBP          (pour sauvegarder EBP)
  2. mov EBP, ESP      (EBP = Sommet de la pile)
  3. mov EAX, [EBP+8]  (Bah oui EBP+4 contient EIP donc c +8 pour mettre A dans eax)
  4. mov EBX, [EBP+12] (pour mettre B dans EBX, puis ainsi de suite)
  5. ...
  6. pop EBP
  7. ret


 
Et là ca marche  :)  
 
Maintenant me faudrait recupérer les donner du code asm vers le prog C. Si quelqu'un connait la procédure qui est utilisé ce serait cool :)  
 
Si quelqu'un sait aussi comment sont passées les structure ce serait bien aussi qu'il m'explique. Pour l'instant j'ai pas encore bcp tester mais j'ai l'impression qu'on empile tous les membre de la struct [:totoz] (mais j'ai pas capter dans quel ordre)

Reply

Marsh Posté le 01-12-2002 à 08:28:23    

EIP :??:
 
Mais kesskidi ?
 
Ah ok, ESP, ton Stack pointer...
 
:sarcastic:


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 01-12-2002 à 10:46:47    

Il y a une norme pour ça, il va peut-être falloir que tu cherches un peu pour trouver la bonne réponse. Voici ce qu'en j'en sais en attendant :
 
- Tout les résultats qui tiennent sur un registre ( int, char, void * ... ) passent leur résultat sur EAX.
- Ta struct doit avoir en mémoire exactement la même organisation que si elle avait été allouée sur le tas.
 
PS : Pourquoi tu met ESP dans EBP ? Il me semble que faire MOV EAX,[ESP+4] ça marche très bien aussi et c'est pas plus lent, non ?

Reply

Marsh Posté le 01-12-2002 à 11:43:38    

Kristoph:ESP n'est pas un registre d'indexe donc on est obligé de passer par EBP.
Meme qd le resultat tient sur un int j'arrive pas à le recup dans EAX. J'ai l'impression que c passer par pile aussi
 
Tetedeiench: EIP Bah oui on empile toujour l'adresse de retour.
 

Code :
  1. f1()
  2. {
  3. int a,b;
  4. ...
  5. f2(a,b);
  6. a=b;
  7. ...
  8. }
  9. f2(int a, int b)
  10. {
  11. ...
  12. }
  13. Etat de la pile au moment de l'apelle de f2
  14. [....] <-- ESP
  15. [....]
  16. [....]
  17. Appelle de f2
  18. [ EIP] <-- ESP EIP = adresse de l'instruction a=b
  19. [  A ]
  20. [  B ]
  21. [....]
  22. [....]
  23. [....]

Reply

Marsh Posté le 01-12-2002 à 11:59:45    

pour le passage de param, fouille dans la msdn, y'a un article qui décrit tres bien ca. (par contre pour ce genre de sport il déconseille _fastcall car c + chiant de retrouver ou sont les paramètres)
 
le retour se fait comme ca (du moins, sous visu)
 
taille du type de retour :
 
4o : retour dans EAX
8o : retour dans EDX:EAX
+8 : passage a ta fonction d'un pointeur vers la structure de retour, pointeur stocké dans EAX. Donc tu colles le resultat a l'adresse mémoire pointé par ledit pointeur
 
 
Par contre, gaffe, parfois visu fait des trucs louche. J'avais une structure de 8o, mais vu qu'y avait des fonction dedans, visu la passait comme une struct de taille supérieur
 
 
si tu veux appeler des fonctions de type __thiscall, il te faut mettre "this" dans edx (tjs sous visu)
 
Pense a cleaner la pile a la fin de ta fonction, aussi


Message édité par chrisbk le 01-12-2002 à 12:03:57
Reply

Marsh Posté le 01-12-2002 à 13:08:07    

sombresonge a écrit a écrit :

Kristoph:ESP n'est pas un registre d'indexe donc on est obligé de passer par EBP.
Meme qd le resultat tient sur un int j'arrive pas à le recup dans EAX. J'ai l'impression que c passer par pile aussi




 
As tu seulement essayé d'utiliser [ESP+4] ? Depuis le 386 on peut utiliser pratiquement n'importe quel registre comme registre d'indirection, et même faire des truc plus sioux encore.

Reply

Marsh Posté le 01-12-2002 à 13:08:07   

Reply

Marsh Posté le 01-12-2002 à 17:02:28    

EBP est le "frame" pointer pour les compilos C/C++, en fait les "anciens" compilos n'étaient pas capable de maintenir/réévaluer l'offset des paramètres dans la pile au fur et à mesure que des données/structures étaint "alloués" sur la pile.....
 
ils faisaient donc un truc style:
 
func:
   
push ebp
mov ebp,esp
 
push eax
 
mov eax,[ebp+....] ;// accès à un paramètre
...
sub esp,16 ;// allocation de 4 longs
...
mov DWORD PTR[esp],edx ;// copie d'un registre dans un long "alloué"
...
pop eax
 
pop ebp
ret
 
alors que maintenant les compilos savent tout faire par esp...

Reply

Marsh Posté le 01-12-2002 à 17:06:57    

Autant que je me souvienne, il doit etre possible de faire des trucs de ce genre sur 386
 
MOV EAX,[ESP+8*EBX]
 
Alors se limiter à EBX ;)

Reply

Marsh Posté le 05-12-2002 à 03:37:18    

bjone a écrit a écrit :

EBP est le "frame" pointer pour les compilos C/C++, en fait les "anciens" compilos n'étaient pas capable de maintenir/réévaluer l'offset des paramètres dans la pile au fur et à mesure que des données/structures étaint "alloués" sur la pile.....
 
ils faisaient donc un truc style:
 
func:
   
push ebp
mov ebp,esp
 
push eax
 
mov eax,[ebp+....] ;// accès à un paramètre
...
sub esp,16 ;// allocation de 4 longs
...
mov DWORD PTR[esp],edx ;// copie d'un registre dans un long "alloué"
...
pop eax
 
pop ebp
ret
 
alors que maintenant les compilos savent tout faire par esp...




 
Oui, mais le nom meme ebp viens de sa fonction primaire :
 
ebp = Base Pointer
esp = Stack pointer ( eip c'est pour ca que ca me fait marrer :lol: )
 
Donc forcement :)
 
De plus, vous utilisez gcc sous linux, il vous pondera un joli
 
push %ebp
movl %ebp, %esp
 
du plus bel effet :)
 


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-12-2002 à 11:03:29    

au lieu de transmettre la valeur de ta variable à l'ASM tu passse la référence mémoire de ta variable.
 
et pares tu écris directement depuis l'assembleur dans ton adresse memoire.


---------------
Damien Moser - http://www.webmaster-ressources.net - http://www.ax-soft.com/fr - ...et vive la suisse!
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed