7
votes

GCC - Comment réaligner la pile?

J'essaie de construire une application qui utilise le type Pthreads et __M128 SSE. Selon le manuel GCC, l'alignement de la pile par défaut est de 16 octets. Pour utiliser __M128, l'exigence est l'alignement de 16 octets.

Mon CPU cible prend en charge SSE. J'utilise un compilateur GCC qui ne prend pas en charge le réalignement d'exécution de la pile d'exécution (par exemple, -Mstackrealign). Je ne peux pas utiliser d'autre version du compilateur GCC.

Mon application de test ressemble à: xxx

L'application génère une exception et des sorties. Après un simple débogage (printf "% p", & y), j'ai trouvé que la variable y n'est pas 16 octets alignée.

Ma question est la suivante: Comment puis-je réaligner la pile correctement (16 octets) Sans utiliser aucun drapeau et attributs de GCC (ils n'aident pas)? Dois-je utiliser un assembleur en ligne GCC dans cette fonction de thread f ()?


1 commentaires

Si vous devez utiliser une version de GCC particulière, veuillez inclure la version GCC (par exemple GCC 4.3.2 I386) et OS hôte / cible (E.G. Debian 5.0 (Lenny) Linux 2.6.26 I686). Savoir s'il faut suggérer que les options GCC 4.3 par rapport à 3.4 peuvent faire une différence.


5 Réponses :


3
votes

Cela ne devrait pas se produire en premier lieu, mais pour contourner le problème, vous pouvez essayer:

void *f(void *x)
{
   __m128 y __attribute__ ((aligned (16)));
   ...
}


5 commentaires

Non, ça n'aide pas. Le même problème.


Je suppose que vous faites cela sur Windows plutôt qu'un système d'exploitation approprié? Il y a quelques bonnes informations sur le travail autour de ce problème: Sourceware.org/ ML / Pthreads-Win32 / 2008 / msg00056.html


Il semble que ceci est un bug dans les anciennes versions de GCC - il semble avoir été fixé vers 2004 - existe-t-il une raison pour laquelle vous ne pouvez pas utiliser une boîte à outils plus à jour?


En fait, non, je ne peux pas utiliser une autre version GCC - nous avons un environnement matériel / logiciel spécifique.


J'essaie d'implémenter un ajustement explicite de la pile à l'aide de l'assembleur en ligne.



7
votes

allouer sur la pile d'un tableau de 15 octets plus grand que Tailleof (__ M128) et utilisez la première adresse alignée dans ce tableau. Si vous en avez besoin de plusieurs, allouez-les dans une matrice avec une marge unique de 15 octets pour l'alignement.

Je ne me souviens pas si vous allociez un tableau non signé le tableau vous permet de protéger des optimisations d'aliasing strictes par le compilateur ou si cela ne fonctionne que l'inverse de l'inverse. xxx


6 commentaires

Vous voudrez peut-être également examiner si la pile de threads globale est allouée à un alignement de 16 octets.


Merci, mais qu'est-ce que pTR_T et pourquoi utilisez-vous et ~ 15?


Malheureusement, cela oblige la variable à être sur la pile, quelles que soient les optimisations potentielles du compilateur (comme la garder dans un registre).


Je suppose que c'est censé être uintptr_t , mais de toute façon, il s'agit simplement d'un type d'entier suffisamment grand pour contenir un pointeur.


@Paul r droit, je cherchais le bon fichier d'en-tête et je ne pouvais pas le trouver parce que je me souviens mal du nom. @psihodelia & ~ 15 signifie "arrondir jusqu'au multiple de 16 immédiatement inférieur".


Cela ne fonctionne pas pour moi, car j'ai beaucoup de fonctions imbriquées et de variables locales.



-2
votes

J'ai résolu ce problème. Voici ma solution:

void another_function(){
   __m128 y;
   ...
}
void *f(void *x){
asm("pushl    %esp");
asm("subl    $16,%esp");
asm("andl    $-0x10,%esp");
another_function();
asm("popl %esp");
}


4 commentaires

Sérieusement. Mettez à jour votre compilateur. Ne soyez pas fier de vous pour mettre des périphériques Rube Goldberg dans votre code.


Ce code semble sauvegarder ESP sur la pile, puis bouger ESP ailleurs, puis pop esp. Cela entraînera une valeur aléatoire dans l'ESP. Cela ne caque-t-il pas un crash? Ou utilisez-vous une convention appelante où ESP est sauvée ailleurs, peut-être dans EBP et restauré à la fin, ce qui rendait ce pop superflu?


1) Je ne peux pas mettre à jour GCC -> J'ai un environnement d'exécution spécifique et un processeur spécifique compatible X86. 2) Non, pourquoi peut-il causer un crash? Économisez ESP, puis la restaurée ne provoque aucun crash ni une valeur aléatoire. J'ai testé le code ci-dessus aussi sans push / POPL et c'est aussi ok. Aucune convention appelante et ESP n'est enregistrée ailleurs.


Comme User9876 a déclaré - Savez-vous ce qu'est-ce que "pushl% esp"? Conceptuellement, cela fonctionne comme ceci: mémoire [% ESP] =% ESP% ESP - = 4; // En fonction de la façon dont votre pile grandit, il peut s'agir de "+ = 4" alors, un "POPL% ESP" fait essentiellement:% ESP + = 4; % ESP = mémoire [% ESP] MAINTENANT, si entre le "PUSH" et "POP", vous avez modifié ESP - le deuxième accès à la mémoire (la "pop") lira à partir d'une mauvaise adresse. La seule explication raisonnable pour la raison pour laquelle cela fonctionne est que le compilateur sauve un% ESP ailleurs également (par exemple dans EBP?) Dans le prologue de la fonction F (), puis la restaure dans l'épilogue de F (). Ainsi, il cache votre erreur.



2
votes

Une autre solution serait, d'utiliser une fonction de rembourrage, qui aligne d'abord la pile, puis appelle f . Donc au lieu d'appeler f directement, vous appelez pad , quels pads la pile d'abord, puis appelle foo avec une pile alignée.

Le Le code ressemblerait à ceci: xxx


0 commentaires

3
votes

Désolé de ressusciter un vieux fil ...

Pour ceux avec un nouveau compilateur que OP, OP mentionne une option -MStackrealign , qui me conduit à __ attribut __ ((forcer_align_arg_pointer)) . Si votre fonction est optimisée pour utiliser SSE, mais % ebp est mal aligné, cela fera les corrections d'exécution si nécessaire pour vous, de manière transparente. J'ai également découvert que ce n'est qu'un problème sur i386 . Le x86_64 abi garantit les arguments sont alignés sur 16 octets.

__ attribut __ ((forcer_align_arg_pointer)) void i_crash_when_not_aligned_to_16_bytes () { ... }

Article cool pour ceux qui voudront peut-être en savoir plus: http://wiki.osdev.org/system_v_abi < / a>