2009-09-25 7 views
10

Je commence avec assembleur sous Linux. J'ai enregistré le code suivant comme testasm.c
et l'a compilé avec: gcc testasm.c -otestasm
Le compilateur répond: "impossible contrainte dans 'asm'".Erreur d'assembleur Linux "contrainte impossible dans 'asm'"

#include <stdio.h> 
int main(void) 
{ 
    int foo=10,bar=15; 

    __asm__ __volatile__ ("addl %%ebx,%%eax" 
     : "=eax"(foo) 
     : "eax"(foo), "ebx"(bar) 
     : "eax" 
    ); 

    printf("foo = %d", foo); 

    return 0; 
} 

Comment puis-je résoudre ce problème? (je l'ai copié l'exemple de here.)

Debian Lenny, noyau 2.6.26-2-amd64
version gcc 4.3.2 (Debian 4.3.2-1.1)

Résolution:
Voir la réponse acceptée - il semble que la clause 'modified' n'est plus supportée.

Répondre

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

semble fonctionner. Je crois que la syntaxe pour les contraintes de registre a changé à un moment donné, mais ce n'est pas très bien documenté. Je trouve plus facile d'écrire l'assemblage brut et éviter les tracas.

+0

Cela fonctionne, merci. On dirait qu'il n'aime plus la clause 'modified', donc je suppose que je vais devoir pousser et popl ce que je change. – slashmais

+2

La clause modifiée fonctionne toujours; Je pense que le problème est que "output" spécifie implicitement "modified", donc avoir eax représenté dans les deux champs était à l'origine du problème. –

0

Si l'on veut utiliser multiligne, cela travaillera également ..

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

« \ » doit être ajouté au compilateur d'accepter une chaîne multiligne (les instructions).

+0

Ce n'est pas un très bon conseil. Vous spécifiez les registres à utiliser dans les listes d'entrée et de sortie, mais utilisez toujours des registres codés en dur dans le bloc d'assemblage réel. Vous devriez utiliser '% 0' et'% 1' à la place. –

+0

@DanielKamilKozar: La réponse acceptée avait tout en une seule ligne. Donc, j'ai utilisé le même code/similaire pour montrer comment le faire en multiline. Je n'ai pas essayé de modifier les registres codés en dur utilisés dans la réponse acceptée originale car je pensais que ce serait plus facile à comprendre quand on compare la ligne multi à simple. –

5

Les contraintes sont simple lettres (éventuellement avec des décorations supplémentaires), et vous pouvez spécifier plusieurs alternatives (c'est-à-dire, un opérande ou un registre intermédiaire est "ir"). Ainsi, la contrainte "eax" désigne les contraintes "e" (constante entière signée de 32 bits), "a" (registre eax), ou "x" (tout registre SSE). C'est un peu différent que ce que OP voulait dire ... et sortie à un "e" n'a clairement aucun sens. De même, si un opérande (dans ce cas une entrée et une sortie) doit être identique à un autre, vous vous référez à lui par une contrainte de nombre. Il n'y a pas besoin de dire que eax sera bousculé, c'est une sortie. Vous pouvez vous référer aux arguments dans le code en ligne par% 0,% 1, ..., pas besoin d'utiliser des noms de registre explicites. Ainsi, la version correcte du code comme prévu par OP serait:

#include <stdio.h> 

int main(void) 
{ 
    int foo=10, bar=15; 

    __asm__ __volatile__ (
     "addl %2, %0" 
     : "=a" (foo) 
     : "0" (foo), "b" (bar) 
    ); 

    printf("foo = %d", foo); 

    return 0; 
} 

Une meilleure solution serait de permettre 2% d'être quoi que ce soit, et 0% d'un registre (comme x86 permet, mais vous auriez à vérifiez le manuel de votre machine):

#include <stdio.h> 

int main(void) 
{ 
    int foo=10, bar=15; 

    __asm__ __volatile__ (
     "addl %2, %0" 
     : "=r" (foo) 
     : "0" (foo), "g" (bar) 
    ); 

    printf("foo = %d", foo); 

    return 0; 
}