Je n'arrive pas à comprendre le rôle joué par les contraintes dans l'assemblage en ligne GCC (x86). J'ai read the manual, qui explique exactement ce que chaque contrainte fait. Le problème est que même si je comprends ce que chaque contrainte fait, je comprends très peu pourquoi vous utiliseriez une contrainte plutôt qu'une autre, ou quelles seraient les implications. Je me rends compte que c'est un sujet très vaste, donc un petit exemple devrait aider à affiner le focus. Ce qui suit est une routine asm simple qui ajoute simplement deux nombres. Si un débordement d'entier se produit, il écrit une valeur de 1
dans une variable de sortie C.Assemblage en ligne GCC: contraintes
int32_t a = 10, b = 5;
int32_t c = 0; // overflow flag
__asm__
(
"addl %2,%3;" // Do a + b (the result goes into b)
"jno 0f;" // Jump ahead if an overflow occurred
"movl $1, %1;" // Copy 1 into c
"0:" // We're done.
:"=r"(b), "=m"(c) // Output list
:"r"(a), "0"(b) // Input list
);
Maintenant, cela fonctionne très bien, sauf que je devais jouer du violon arbitraire avec les contraintes jusqu'à ce que je l'ai eu à travailler correctement. A l'origine, je les contraintes suivantes:
:"=r"(b), "=m"(c) // Output list
:"r"(a), "m"(b) // Input list
Notez qu'au lieu d'un « 0 », j'utilise une contrainte « m » pour b
. Cela a eu un effet secondaire étrange où si je compilé avec des indicateurs d'optimisation et appelé la fonction deux fois, pour une raison quelconque le résultat de l'opération d'addition serait également stocké dans c
. J'ai fini par lire "matching constraints", ce qui vous permet de spécifier qu'une variable doit être utilisée comme opérande d'entrée et de sortie. Quand j'ai changé "m"(b)
à "0"(b)
cela a fonctionné.
Mais je ne comprends pas vraiment pourquoi vous utiliseriez une contrainte plutôt qu'une autre. Je veux dire oui, je comprends que "r" signifie que la variable devrait être dans un registre et "m" signifie qu'il devrait être en mémoire - mais je ne comprends pas vraiment les implications de choisir un sur un autre, ou pourquoi l'opération d'addition ne fonctionne pas correctement si je choisis une certaine combinaison de contraintes.
Questions: 1) Dans l'exemple de code ci-dessus, pourquoi la contrainte "m" sur b
a-t-elle entraîné l'écriture de c
? 2) Existe-t-il des tutoriels ou des ressources en ligne qui détaillent les contraintes?
Merci - c'est une excellente réponse. Juste une précision: pourquoi le modificateur de contrainte '=' (en écriture seule) donne-t-il au compilateur le droit de réutiliser le même emplacement mémoire, même si 'b' et' c' sont des variables différentes avec des emplacements différents en mémoire? – Channel72
@ Channel72: "même si' b' et 'c' sont des variables différentes avec des emplacements différents en mémoire" --- c'est en fait une hypothèse majeure, qui souvent ne s'applique pas. Si 'b' et' c' sont des variables locales, il y a de fortes chances qu'ils soient tous deux sauvegardés par des registres, plutôt que par un emplacement mémoire. Dans ce cas, l'emplacement de mémoire est simplement un emplacement temporaire qui est configuré uniquement pour s'adapter à votre contrainte 'm' --- dans ce cas,' b' et 'c' pourraient très bien utiliser le même emplacement temporaire. –
Maintenant, si 'b' et' c' étaient réellement tous les deux vraiment sauvegardés par des emplacements de mémoire, alors vous auriez raison, normalement ils ne devraient pas se chevaucher du tout. Et, si l'un est soutenu par la mémoire et l'autre est soutenu par le registre ... alors l'un ou l'autre de ces scénarios est possible. –