Fonction d’appel avec float dans l’assemblage x86 x87

Je suis novice en programmation d’assemblage et, en tant que partie d’un programme plus important, j’ai besoin de transmettre des valeurs à virgule flottante à une autre fonction C. J’ai un appel de mon programme de test à ma fonction d’assemblage, qui ne fait que pousser les parameters sur la stack de droite et appelle une deuxième fonction C.

Ma fonction de test C:

extern void ext_func(char *result, double d); // C function extern double tester(char *str, float d); double a = tester(str, 3.14) printf("%s\n", str); // Resulting in '0.000000' // doing some fancy stuff with the float value and puts in result ext_func(str, 3.14); // gives str = "3.140000" 

x86, gcc -m32:

  .globl tester tester: pushl %ebp # Standard movl %esp, %ebp # flds 12(%ebp) # Push second parameter on stack pushl 8(%ebp) call ext_func addl $4, %esp leave ret 

Je pense qu’il y a un problème avec moi qui pousse seulement 32 bits quand ext_funct attend le double. Mais j’ai essayé d’utiliser le fldl, fld1, fildl, les fldl 12 et 16 (% ebp), et quelques-uns des autres pour “fun”.

  • Ma première question est la suivante: manque-t-il des données dans ext_func sur la stack flottante (ST) et ne peut-il donc pas créer la valeur float?
  • Deuxièmement, le compilateur accède-t-il toujours à la stack f pour obtenir des valeurs float s’il les attend, ou est-il possible de les lire à partir de la stack de mémoire?
  • Troisièmement, y a-t-il autre chose qui me manque ici? Si je
 printf("%f", a); //3.140000 printf("%f", str); //3.140000 

mais dans l’autre voie, a grand nombre négatif (100 chiffres environ) se termine par 000000.

La convention 32 bits utilise la stack cpu pour transmettre des arguments en virgule flottante. Il utilise uniquement la stack fpu pour les retourner. Oui, vous devez convertir votre float 32 bits en un double 64 bits, conformément aux prototypes fournis.

Notez que ext_func est void , c’est-à-dire qu’il ne retourne rien, mais que vous avez déclaré le tester comme renvoyant double … on ne sait pas exactement ce que vous voulez renvoyer, je supposerai que vous voulez que le d original soit renvoyé (pour une raison quelconque).

A ce titre, une implémentation possible pourrait être:

  .globl tester tester: subl $12, %esp # allocate space for outgoing arguments movl 16(%esp), %eax # fetch our first argument (str) movl %eax, (%esp) # store as first outgoing argument flds 20(%esp) # Fetch our second argument as float fstpl 4(%esp) # store it as second outgoing argument as double call ext_func flds 20(%esp) # load d as return value addl $12, %esp # cleanup stack ret