2017-02-16 2 views
0

programme envisager de suivre:dans l'assemblage en ligne

#include <stdio.h> 
int main(void) { 
     int foo = 10, bar = 15; 
     __asm__ __volatile__("add %%ebx,%%eax" 
          :"=a"(foo) 
          :"a"(foo), "b"(bar) 
          ); 
     printf("foo+bar=%d\n", foo); 
} 

Je sais que l'instruction add est utilisé pour l'addition, l'instruction sub est utilisé pour la soustraction & ainsi de suite. Mais je ne comprenais pas ces lignes:

__asm__ __volatile__("add %%ebx,%%eax" 
          :"=a"(foo) 
          :"a"(foo), "b"(bar) 
          ); 

Quelle est la signification exacte de :"=a"(foo) :"a"(foo), "b"(bar));? Ce qu'il fait ? Et quand je tente d'utiliser l'instruction mul ici je suis l'erreur suivante pour le programme suivant:

#include <stdio.h> 
int main(void) { 
     int foo = 10, bar = 15; 
     __asm__ __volatile__("mul %%ebx,%%eax" 
          :"=a"(foo) 
          :"a"(foo), "b"(bar) 
          ); 
     printf("foo*bar=%d\n", foo); 
} 

Erreur: nombre de non-concordance des opérandes pour `mul »

Alors, pourquoi je reçois cette erreur? Comment puis-je résoudre cette erreur? J'ai cherché sur Google à ce sujet, mais je n'ai pas trouvé de solution à mon problème. J'utilise Windows 10 os processeur & est intel core i3.

Répondre

4

What is the exact meaning of :"=a"(foo) :"a"(foo), "b"(bar));

Il y a une description détaillée de la façon dont les paramètres sont transmis à l'instruction asm here. En bref, cela signifie que bar va dans le registre ebx, foo entre dans eax, et après l'exécution de asm, eax contiendra une valeur mise à jour pour foo.

Error: number of operands mismatch for `mul'

Ouais, ce n'est pas la bonne syntaxe pour mul. Vous devriez peut-être passer du temps avec un manuel de référence de l'assembleur x86 (par exemple, this).

J'ajouterai également que l'utilisation d'inline asm est généralement bad idea.


Modifier: Je ne peux pas répondre à votre commentaire dans votre commentaire.

Je ne sais pas par où commencer. Ces questions semblent indiquer que vous n'avez pas une très bonne compréhension de la façon dont l'assembleur fonctionne. Essayer de vous enseigner la programmation ASM dans une réponse SO n'est pas vraiment pratique.

Mais je peux vous orienter dans la bonne direction.

D'abord, pensez à ce morceau de code asm:

movl $10, %eax 
movl $15, %ebx 
addl %ebx, %eax 

Comprenez-vous ce que cela fait? Que sera dans eax quand cela sera terminé? Que sera dans ebx? Maintenant, comparez cela avec ceci:

int foo = 10, bar = 15; 
__asm__ __volatile__("add %%ebx,%%eax" 
        :"=a"(foo) 
        :"a"(foo), "b"(bar) 
        ); 

En utilisant la « une » contrainte, vous demandez gcc pour déplacer la valeur de foo dans eax. En utilisant la contrainte "b" vous lui demandez de déplacer bar en ebx. Il le fait, puis exécute les instructions pour l'asm (c.-à-d. add). A la sortie de l'asm, la nouvelle valeur pour foo sera dans eax. Trouver? Maintenant, regardons mul. D'après les documents auxquels je vous ai relié, nous savons que la syntaxe est mul value. Cela semble étrange, n'est-ce pas? Comment peut-il y avoir seulement un paramètre à mul?Qu'est-ce que multiple la valeur avec? Mais si vous continuez à lire, vous voyez "Toujours multiplier EAX par une valeur." Ahh. Donc le registre "eax" est toujours implicite ici. Donc, si vous deviez écrire mul %ebx, ce serait vraiment mul ebx, eax, mais comme a toujours, il n'y a aucun intérêt à l'écrire.

Cependant, c'est un peu plus compliqué que cela. ebx peut contenir un numéro de valeur 32bit. Puisque nous utilisons ints (au lieu de ints non signés), cela signifie que ebx pourrait avoir un nombre aussi grand que 2 147 483 647. Mais attendez, que se passe-t-il si vous multipliez 2 147 483 647 * 10? Eh bien, puisque 2 147 483 647 est déjà un nombre aussi grand que vous pouvez stocker dans un registre, le résultat est beaucoup trop grand pour tenir dans eax. Donc la multiplication (toujours) utilise 2 registres pour sortir le résultat de mul. C'est ce que ce lien signifiait quand il se référait "stocke le résultat dans EDX: EAX".

Ainsi, vous pouvez écrire votre multiplication comme ceci:

int foo = 10, bar = 15; 
int upper; 
__asm__ ("mul %%ebx" 
     :"=a"(foo), "=d"(upper) 
     :"a"(foo), "b"(bar) 
     :"cc" 
     ); 

Comme précédemment, ce qui met la barre dans EBX et foo dans eax, exécute alors l'instruction de multiplication.

Et après que l'asm soit terminé, eax contiendra la partie inférieure du résultat et edx contiendra la partie supérieure. Si foo * bar < 2 147 483 647, alors foo contiendra le résultat dont vous avez besoin et upper sera zéro. Sinon, les choses deviennent plus compliquées.

Mais c'est aussi loin que je suis prêt à aller. Autre que cela, prenez une classe ASM. Lire un livre. PS Vous pouvez également regarder this réponse et les 3 commentaires qui suivent qui montrent pourquoi même votre "ajouter" exemple est "faux". PPS Si cette réponse a résolu votre question, n'oubliez pas de cliquer sur la coche à côté de celle-ci pour obtenir mes points de karma.

+0

Que signifie «a» et «b» ici? – Destructor

+0

Si vous lisez les documents auxquels je suis lié pour asm, vous verrez que les chaînes entre guillemets sont des "contraintes" qui décrivent comment mapper les variables du langage C vers quelque chose que vous pouvez comprendre (voir la section i386 [ici] (https: // gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html)). "a" se réfère au registre eax. "b" se réfère à ebx. –

+0

ok merci. Je l'ai. Mais j'ai toujours un problème. Je veux multiplier les valeurs des variables foo & bar et stocker le résultat dans foo. J'ai visité le lien que vous avez donné à propos de l'insertion multi, mais j'ai encore du mal à savoir ce que je devrais faire exactement pour y parvenir? – Destructor