2016-02-04 1 views
-2

I ont la partie suivante dans mon asm code assembleur(montage en ligne dans C) d'erreur de segmentation de mémoire amusant

"LOOP%=:\n\t" 
     "movapd (%%eax), %%xmm4\n\t" 
     "addl $32, %%eax\n\t" 
     "movsd (%%edx), %%xmm5\n\t" 
     "addl $16, %%edx\n\t" 
     "movapd %%xmm4, %%xmm6\n\t" 
     "subl $1, %%ecx\n\t" 
     "unpcklpd %%xmm5, %%xmm5\n\t" 
     "testl %%ecx, %%ecx\n\t" 
     "mulpd %%xmm5, %%xmm6\n\t" 
     "movsd -8(%%edx), %%xmm7\n\t" 
     "addpd %%xmm6, %%xmm0\n\t" 
     "movapd -16(%%eax), %%xmm6\n\t" 
     "unpcklpd %%xmm7, %%xmm7\n\t" 
     "mulpd %%xmm6, %%xmm5\n\t" 
     "addpd %%xmm5, %%xmm1\n\t" 
     "mulpd %%xmm7, %%xmm4\n\t" 
     "addpd %%xmm4, %%xmm2\n\t" 
     "mulpd %%xmm6, %%xmm7\n\t" 
     "addpd %%xmm7, %%xmm3\n\t" 
     "jne LOOP%=\n\t" */ 

Ce code contient en% ecx un "indice de boucle", tout en balayant deux (double *) les tableaux A et B effectuant un certain calcul en utilisant SSE2. Les deux tableaux ont été alignés sur 64Bytes (alignés sur la ligne de cache de sorte que l'exigence d'alignement de 16 octets de SSE est satisfaite). % eax contient un "pointeur" vers le tableau A et "edx" contient un "pointeur" vers le tableau B. Il fonctionne correctement et il n'y a pas d'erreur de lecture de la mémoire. Je me demande pourquoi dois-je faire

 "movapd (%%eax), %%xmm4\n\t" 
     "addl $32, %%eax\n\t" 
     "movsd (%%edx), %%xmm5\n\t" 
     "addl $16, %%edx\n\t" 
     ...... 
     "movsd -8(%%edx), %%xmm7\n\t" 
     ...... 
     "movapd -16(%%eax), %%xmm6\n\t" 
     ...... 

Je changer la version initiale à

"LOOP%=:\n\t" 
     "movapd (%%eax), %%xmm4\n\t" 
     "movsd (%%edx), %%xmm5\n\t" 
     "movapd %%xmm4, %%xmm6\n\t" 
     "subl $1, %%ecx\n\t" 
     "unpcklpd %%xmm5, %%xmm5\n\t" 
     "testl %%ecx, %%ecx\n\t" 
     "mulpd %%xmm5, %%xmm6\n\t" 
     "movsd 8(%%edx), %%xmm7\n\t" 
     "addl $16, %%edx\n\t" 
     "addpd %%xmm6, %%xmm0\n\t" 
     "movapd 16(%%eax), %%xmm6\n\t" 
     "addl $32, %%eax\n\t" 
     "unpcklpd %%xmm7, %%xmm7\n\t" 
     "mulpd %%xmm6, %%xmm5\n\t" 
     "addpd %%xmm5, %%xmm1\n\t" 
     "mulpd %%xmm7, %%xmm4\n\t" 
     "addpd %%xmm4, %%xmm2\n\t" 
     "mulpd %%xmm6, %%xmm7\n\t" 
     "addpd %%xmm7, %%xmm3\n\t" 
     "jne LOOP%=\n\t" 

Mais je souffre d'un défaut de segmentation pour la lecture non valide.

Cela me semble amusant. Pourquoi?

+3

Il serait beaucoup plus rapide pour vous d'exécuter cela sous un débogueur et voir quelle instruction provoque la faute, puis regardez les registres pour voir ce qu'il faisait au lieu de nous demander. – wallyk

+0

S'il vous plaît ne pas afficher le code sous le titre "segfault", puis dire qu'il fonctionne correctement. –

+0

Je ne vois pas pourquoi vous avez changé le code qui fonctionnait correctement en premier lieu. –

Répondre

2

Ceci est la cause:

"testl %%ecx, %%ecx\n\t" 

Le résultat de ce test est utilisé dans l'état de la boucle à la fin de ce code. Avec le déplacement des opérations d'ajout, vous écrivez les drapeaux pour la condition, donc c'est toujours satisfait et ça marche pour toujours jusqu'à ce que vous quittiez la mémoire.

+3

@AlphaBetaGamma, recherchez chaque instruction que vous utilisez, pour voir quel effet a sur les drapeaux. Certaines opérations définissent divers drapeaux comme sous-produits, d'autres n'en définissent pas (les drapeaux existants subsistent), d'autres ont pour but de définir des drapeaux. –

+1

@AlphaBetaGamma: aussi, il sera plus efficace de placer l'instruction de définition de drapeau juste à côté de la branche conditionnelle, afin qu'ils puissent fusionner en une seule opération de comparaison et de branche en interne dans la CPU. par exemple. 'dec% ecx' /' jnz' sera bon. Voir http://agner.org/optimize/ –

+0

@PeterCordes: Ceci est contraire aux techniques d'optimisation utilisées dans les années 1990. Là, on séparerait le réglage du drapeau du test par une instruction ou deux afin que des pipelines séparés puissent progresser et aucun ne serait bloqué en attente d'un calcul. – wallyk