Assemblage en boucle à travers une chaîne pour compter les caractères

J’essaie de faire un code d’assemblage qui compte combien de caractères est dans la chaîne, mais j’obtiens une erreur.

Code, j’utilise gcc et intel_syntax

#include  int main(){ char *s = "aqr b qabxx xryc pqr"; int x; asm volatile ( ".intel_syntax noprefix;" "mov eax, %1;" "xor ebx,ebx;" "loop:" "mov al,[eax];" "or al, al;" "jz print;" "inc ebx;" "jmp loop" "print:" "mov %0, ebx;" ".att_syntax prefix;" : "=r" (x) : "r" (s) : "eax", "ebx" ); printf("Length of ssortingng: %d\n", x); return 0; } 

Et j’ai eu une erreur:

 Error: invalid use of register 

Enfin, je souhaite créer un programme qui recherche le motif regex ([pq] [^ a] + a) et l’imprime en position de départ et en longueur. Je l’ai écrit en C, mais je dois le faire fonctionner en assembleur: Mon code C:

 #include  #include  int main(){ char *s = "aqr b qabxx xryc pqr"; int y,i; int x=-1,length=0, pos = 0; int len = strlen(s); for(i=0; i<len;i++){ if((s[i] == 'p' || s[i] == 'q') && length0){ length++; } else if((s[i] == 'a') && pos>0){ length++; if(y < length) { y=length; length = 0; x = pos; pos = 0; } else length = 0; pos = 0; } } printf("position: %d, length: %d", x, y); return 0; } 

Vous avez omis le point-virgule après la jmp loop et print: jmp loop


De plus, votre asm ne fonctionnera pas correctement. Vous déplacez le pointeur sur s dans eax, mais vous l’écrasez ensuite avec mov al,[eax] . Ainsi, lors du prochain passage dans la boucle, eax ne pointe plus la chaîne.

Et lorsque vous corrigez cela, vous devez penser au fait que chaque passage dans la boucle doit changer eax pour pointer vers le caractère suivant, sinon mov al,[eax] continue à lire le même caractère.


Puisque vous n’avez pas encore accepté de réponse (en cliquant sur la coche à gauche), il vous rest encore du temps pour une nouvelle édition.

Normalement, je ne fais pas les devoirs des gens, mais ça fait quelques jours. Vraisemblablement, la date d’échéance de la mission est passée. Dans ce cas, voici quelques solutions, à la fois pour l’éducation du PO et pour les futurs utilisateurs de SO:

1) Respecter les limites (quelque peu étranges) de la mission:

 asm volatile ( ".intel_syntax noprefix;" "mov eax, %1;" "xor ebx,ebx;" "cmp byte ptr[eax], 0;" "jz print;" "loop:" "inc ebx;" "inc eax;" "cmp byte ptr[eax], 0;" "jnz loop;" "print:" "mov %0, ebx;" ".att_syntax prefix;" : "=r" (x) : "r" (s) : "eax", "ebx" ); 

2) Enfreindre certaines des règles d’atsortingbution pour améliorer légèrement le code:

 asm ( "\n.intel_syntax noprefix\n\t" "mov eax, %1\n\t" "xor %0,%0\n\t" "cmp byte ptr[eax], 0\n\t" "jz print\n" "loop:\n\t" "inc %0\n\t" "inc eax\n\t" "cmp byte ptr[eax], 0\n\t" "jnz loop\n" "print:\n" ".att_syntax prefix" : "=r" (x) : "r" (s) : "eax", "cc", "memory" ); 

Ceci utilise 1 registre de moins (pas d’ ebx ) et omet le qualificatif volatile (inutile). Il ajoute également le segment “cc” pour indiquer que le code modifie les indicateurs et utilise le segment “mémoire” pour s’assurer que toute écriture “en attente” dans s est vidée en mémoire avant l’exécution de la commande asm. Il utilise également le formatage (\ n \ t) pour que le résultat de la construction avec -S soit lisible.

3) La version avancée qui utilise encore moins de registres (pas eax ), vérifie que s n’est pas NULL (renvoie -1), utilise des noms symboliques et suppose -masm=intel ce qui donne un code plus lisible:

 __asm__ ( "test %[ssortingng], %[ssortingng]\n\t" "jz print\n" "loop:\n\t" "inc %[length]\n\t" "cmp byte ptr[%[ssortingng] + %[length]], 0\n\t" "jnz loop\n" "print:" : [length] "=r" (x) : [ssortingng] "r" (s), "[length]" (-1) : "cc", "memory" ); 

Se débarrasser des contraintes d’affectation (arbitraires et non bien pensées) nous permet de réduire cela à 7 lignes (5 si nous ne vérifions pas NULL, 3 si nous ne comptons pas les étiquettes [qui ne sont pas réellement des instructions]) .

Il existe des moyens d’améliorer encore cela (utiliser %= sur les étiquettes pour éviter d’éventuels problèmes de symbole en double, utiliser des étiquettes locales ( .L ), voire l’écrire pour que cela fonctionne à la fois -masm=intel et -masm=att , etc. ), mais j’ose dire qu’aucun de ces 3 n’est meilleur que le code de la question initiale.


Eh bien, Kuba, je ne sais pas ce que tu veux de plus avant d’accepter une réponse. Néanmoins, cela me donne la possibilité d’inclure la version de Peter.

4) incrémentation du pointeur:

 __asm__ ( "cmp byte ptr[%[ssortingng]], 0\n\t" "jz .Lprint%=\n" ".Loop%=:\n\t" "inc %[length]\n\t" "cmp byte ptr[%[length]], 0\n\t" "jnz .Loop%=\n" ".Lprint%=:\n\t" "sub %[length], %[ssortingng]" : [length] "=&r" (x) : [ssortingng] "r" (s), "[length]" (s) : "cc", "memory" ); 

Cela ne fait pas la vérification du “pointeur NULL” à partir de # 3, mais cela fait le “incrément de pointeur” que Peter recommandait. Cela évite également les doublons potentiels (en utilisant %= ) et utilise des étiquettes ‘locales’ (celles commençant par .L ) pour éviter que des symboles supplémentaires ne soient écrits dans le fichier object.

D’un sharepoint vue “performance”, cela pourrait être légèrement mieux (je ne l’ai pas chronométré). Toutefois, d’un sharepoint vue “projet d’école”, la clarté de la règle 3 semble être un meilleur choix. Du sharepoint vue “qu’est-ce que j’écrirais dans le monde réel si, pour une raison quelconque, je devais écrire ceci en asm au lieu d’utiliser simplement une fonction c standard”, je regarderais probablement l’utilisation, et à moins que ce soit critique pour la performance , Je serais tenté de choisir le n ° 3 afin de faciliter la maintenance future.