Question

Qu'est-ce que l'alignement est pile? Pourquoi est-il utilisé? Peut-il être contrôlé par les paramètres du compilateur?

Les détails de cette question sont prises à partir d'un problème auquel sont confrontés lorsqu'ils tentent d'utiliser les bibliothèques ffmpeg avec msvc, mais ce que je suis vraiment intéressé par une explication de ce qui est « l'alignement de la pile ».

Les détails:

  • Lorsque runnig mon msvc programme respecté qui lie à avcodec je reçois la l'erreur suivante: « compilateur n'a pas aligner les variables de la pile libavcodec a. été mal compilée », suivi d'un accident dans avcodec.dll.
  • avcodec.dll n'a pas été compilé avec msvc, donc je suis incapable de voir ce qui se passe à l'intérieur.
  • Lors de l'exécution ffmpeg.exe et en utilisant le même tout avcodec.dll fonctionne bien.
  • ffmpeg.exe n'a pas été compilé avec msvc, il a été respecté gcc / MinGW (comme avcodec.dll)

Merci,

Dan

Était-ce utile?

La solution

L'alignement des variables dans la mémoire (une courte histoire).

Dans les ordinateurs passés avait un bus de données 8 bits. Cela signifie que chaque cycle d'horloge de 8 bits d'informations peuvent être traitées. Ce qui était bien alors.

Puis vint 16 ordinateurs bits. En raison de la compatibilité descendante et d'autres questions, l'a été maintenu et a été introduit mot de 16 bits octet 8 bits. Chaque mot était de 2 octets. Et chaque cycle d'horloge de 16 bits d'information peut être traitée. Mais cela pose un petit problème.

Regardons une carte mémoire:

+----+
|0000| 
|0001|
+----+
|0002|
|0003|
+----+
|0004|
|0005|
+----+
| .. |

A chaque adresse il y a un octet accessible individuellement. Mais les mots ne peuvent être récupérées à même les adresses. Donc, si nous lisons un mot à 0000, on lit les octets à 0000 et 0001. Mais si l'on veut lire le mot à la position 0001, nous avons besoin de deux accès en lecture. Tout d'abord 0000,0001 puis 0002,0003 et nous ne gardons que 0001,0002.

Bien sûr, cela a pris un certain temps et qui n'a pas été apprécié. Voilà pourquoi ils ont inventé l'alignement. Nous avons donc stocker des variables de mots aux limites des mots et des variables d'octets aux limites des octets.

Par exemple, si nous avons une structure avec un champ d'octet (B) et un champ de mot (W) (et un compilateur très naïf), nous obtenons les éléments suivants:

+----+
|0000| B
|0001| W
+----+
|0002| W
|0003|
+----+

Ce qui est pas amusant. Mais lorsque vous utilisez l'alignement des mots, nous trouvons:

+----+
|0000| B
|0001| -
+----+
|0002| W
|0003| W
+----+

Ici, la mémoire est sacrifiée pour la vitesse d'accès.

Vous pouvez imaginer que lorsque vous utilisez un double mot (4 octets) ou d'un mot quad (8 octets) ce qui est encore plus important. Voilà pourquoi la plupart des compilateurs modernes, vous pouvez choisir l'alignement que vous utilisez lors de la compilation du programme.

Autres conseils

Certaines architectures CPU exigent un alignement spécifique de différents types de données, et jetteront des exceptions si vous ne respecte pas cette règle. En mode standard, x86 ne nécessite pas pour les types de données de base, mais peut subir des pénalités de performance (vérifier www.agner.org conseils d'optimisation de bas niveau).

Cependant, instruction rel="noreferrer" href="http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions" ensemble (souvent utilisé pour les hautes performances ) procesing audio / vidéo a des exigences strictes d'alignement, et lancer des exceptions si vous essayez de l'utiliser sur des données non alignés (sauf si vous utilisez, sur certains processeurs, beaucoup plus lent versions non alignés).

Votre question est probablement que l'on compilateur attend le appelant de garder la pile alignée, tandis que l'autre attend callee pour aligner la pile lorsque nécessaire.

EDIT : comme la raison pour laquelle l'exception se produit, une routine dans la DLL veut probablement utiliser des instructions SSE sur certaines données de la pile temporaire et échoue parce que les deux différents compilateurs ne sont pas d'accord sur les conventions d'appel .

IIRC, l'alignement de la pile est lorsque les variables sont placés sur la pile « aligné » pour un nombre déterminé d'octets. Donc, si vous utilisez un alignement de la pile de 16 bits, chaque variable sur la pile va commencer à partir d'un octet qui est un multiple de 2 octets du pointeur de pile courante dans une fonction.

Cela signifie que si vous utilisez une variable qui est <2 octets, tel qu'un char (1 octet), il y aura 8 bits inutilisés « padding » entre lui et la variable suivante. Cela permet à certaines optimisations avec des hypothèses basées sur des endroits variables.

Lors de l'appel des fonctions, une méthode consistant à faire passer des arguments à la fonction suivante est de les placer sur la pile (par opposition à les placer directement dans des registres). Si oui ou non l'alignement est utilisé ici est important, car la fonction appelante place les variables sur la pile, à lire au large par la fonction d'appel à l'aide des décalages. Si la fonction appelant aligne les variables et la fonction appelée les attend à être non-alignés, la fonction appelée ne sera pas en mesure de les trouver.

Il semble que le code compilé msvc est en désaccord sur l'alignement variable. Essayez de compiler avec tous Optimisations désactivés.

Pour autant que je sache, les compilateurs ne correspondent généralement pas des variables qui sont sur la pile. La bibliothèque peut être en fonction de certains ensemble d'options du compilateur qui ne sont pas pris en charge sur votre compilateur. Le correctif normale est de déclarer les variables qui doivent être alignées comme statique, mais si vous allez faire cela dans le code d'autres personnes, vous voulez être sûr qu'ils variables en question sont initialisés plus tard dans la fonction plutôt que dans la déclaration.

// Some compilers won't align this as it's on the stack...
int __declspec(align(32)) needsToBe32Aligned = 0;
// Change to
static int __declspec(align(32)) needsToBe32Aligned;
needsToBe32Aligned = 0;

Sinon, trouver un commutateur de compilateur qui aligne les variables sur la pile. Il est évident que la « __declspec » aligner la syntaxe que je l'ai utilisé ici peut ne pas être ce que votre compilateur utilise.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top