bras assembly en ligne dans gcc
J'ai quelques problèmes avec certains assembly en ligne de code. Je sais ce qui doit être fait, mais je m'ennuie de le "comment" !
J'ai cette somme de contrôle de la fonction qui est "presque" de travail :
static unsigned long cksum_unroll( unsigned short **w, int *mlen)
{
int len;
unsigned short *w0;
unsigned long sum=0;
len = *mlen;
w0 = *w;
while( len >= 8) {
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0"
: [sum] "+r" (sum) : [w0] "r" (w0)
);
len -= 8;
}
*mlen = len;
*w = w0;
return (sum);
}
Mon problème, je crois, est sur la ligne ": [somme] "+r" (somme) : [w0] "r" (w0)"
Sur la première ligne d'assemblage, w0 est traitée correctement par ldmia (lorsque la ligne est exécutée, les données sont dans r4,r5 et w0 est incrémenté). Mais la valeur incrémentée de w0 n'est pas enregistré quelque part et lorsque le code de la boucle, la valeur d'origine de w0 est à nouveau chargé (voir le code assembleur ci-dessous).
Ma conjecture est que je doit stocker la valeur de w0 sur la ligne ": [somme] "+r" (somme) : [w0] "r" (w0)" mais je ne sais pas comment...
Voici le démontage, le code de la ligne d'assemblage de la partie de la fonction :
Noter que :
len is stored at r11, #-16
w0 is stored at r11, #-20
sum is stored at r11, #-24
Compilé, le code suivant :
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0"
: [sum] "+r" (sum) : [w0] "r" (w0)
);
len -= 8;
Générer :
00031910: ldr r3, [r11, #-20]
00031914: ldr r2, [r11, #-24]
00031918: mov r4, r2
0003191c: ldm r3!, {r4, r5}
00031920: adds r4, r4, r4
00031924: adcs r4, r4, r5
00031928: adcs r4, r4, #0
0003192c: str r4, [r11, #-24]
00031930: ldr r3, [r11, #-16]
00031934: sub r3, r3, #8
00031938: str r3, [r11, #-16]
Comme vous pouvez le voir, je voudrais ajouter quelque chose comme "str r3, [r11, #-20]" entre les lignes 31928 et 3192c parce que quand la boucle du programme à la ligne 31910, r3 est chargé avec la valeur initiale de la résistance r3...
Je pense que c'est une question facile pour la ligne d'assemblage d'experts de l'débordement de pile de la communauté!
En passant, je suis en train de travailler sur un processeur ARM7TDMI (mais cela peut ne pas être pertinente pour cette question...)
Merci d'avance!
EDIT:
De vérifier mon idée, j'ai testé le suivant :
asm volatile (
"ldmia %[w0]!, {v1, v2}\n\t"
"adds %[sum], %[sum], v1\n\t"
"adcs %[sum], %[sum], v2\n\t"
"adcs %[sum], %[sum], #0\n\t"
"str %[w0], [r11, #-20]"
: [sum] "+r" (sum) : [w0] "r" (w0)
);
Et cela fonctionne. C'est peut-être la solution, mais que dois-je utiliser pour remplacer "r11, n ° 20," qui va probablement changer si je modifie la fonction?
asm volatile ( "ldmia %[w0]!, {v1, v2}\n\t" "adds %[sum], %[sum], v1\n\t" "adcs %[sum], %[sum], v2\n\t" "adcs %[sum], %[sum], #0\n\t" "str %[w0], [r11, #-20]" : [sum] "+r" (sum) : [w0] "r" (w0) );
Et cela fonctionne. C'est peut-être la solution, mais que dois-je utiliser pour remplacer "r11, n ° 20," qui va probablement changer si je modifie la fonction?GCC inline assemblée prend mon mal à la tête (et j'ai déjà on a commencé à cause de certains tapis collant passe à proximité, dans un remodelage), donc je ne peux pas vous donner une aide... Mais je peux point vous l'un des meilleurs docs que j'ai lu sur la façon de traiter avec GCC de l'asm inline, dans le cas où vous n'avez pas rencontré encore: ethernut.de/en/documents/arm-inline-asm.html en bonus, la doc de cibler spécifiquement les BRAS.
Merci pour le lien. Ce web pages était déjà ouvert quand j'ai écrit cette question!
OriginalL'auteur Martin Allard | 2012-02-15
Vous devez vous connecter pour publier un commentaire.
Le problème semble être que vous spécifiez
w0
comme un opérande d'ENTRÉE, alors qu'elle devrait être une lecture-écriture opérande de SORTIE, commesum
. En outre, vous avez besoin de spécifier qu'il clobbers v1 et v2 comme vous l'utilisation de ces registres (sinon, gcc peut mettre quelques autres var dans ces regs et s'attendre à être conservés.)De sorte que vous devriez avoir:
qui est, de deux en lecture-écriture d'entrée/sortie opérandes, pas exclusivement d'entrée d'opérandes, et de deux registre clobbers
:[w0] "+r" (w0), [sum] "+r" (sum)
qui est, sauf pour le clobbers partie, la réponse que vous avez donné, mais avec de la somme et de w0 dans l'ordre inverse... j'ai essayé votre solution sans la clobbers(comme vous l'avez dit que je "devrait", et non "doit" utiliser 😉 et il se comporter comme au début. Avec le clobbers partie, il fonctionne parfaitement comme il force le compilateur à enregistrer l'état de w0!Ok, j'ai renforcé la formulation un peu. En laissant de côté la clobbers est une forme particulièrement insidieuse de bug, car il pourrait très bien fonctionner lorsque vous essayez d'abord, et puis une pause plus tard, lorsque vous modifiez certains (apparemment) sans rapport avec la partie du programme qui perturbe l'allocateur de registres.
OriginalL'auteur Chris Dodd