Les variables de pile sont-elles alignées par le GCC __attribute __ ((alignés (x)))?

StackOverflow https://stackoverflow.com/questions/841433

  •  20-08-2019
  •  | 
  •  

Question

J'ai le code suivant:

#include <stdio.h>

int
main(void)
{
        float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0};
        printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]);
}

Et j'ai la sortie suivante:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac

Pourquoi l'adresse de a [0] n'est pas un multiple de 0x1000 ?

Que fait exactement __ attribut __ ((aligné (x))) ? J'ai mal compris la cette explication?

J'utilise gcc 4.1.2.

Était-ce utile?

La solution

Je pense que le problème est que votre tableau est sur la pile. Parce que le pointeur de pile peut être n'importe quoi au démarrage de la fonction, il n’ya aucun moyen d’aligner le tableau sans en allouer beaucoup plus que nécessaire et sans l’ajuster. Si vous déplacez le tableau hors de la fonction et dans une variable globale, cela devrait fonctionner. Vous pouvez également la conserver en tant que variable locale (ce qui est une très bonne chose), mais définissez-la statique . Cela l'empêchera d'être stocké sur la pile. Attention, ces deux méthodes ne sont ni thread-safe, ni récursives, car il n’y aura qu’une copie du tableau.

Avec ce code:

#include <stdio.h>

float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0};

int
main(void)
{
        printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]);
}

Je reçois ceci:

0x804c000 0x804c004 0x804c008 0x804c00c

qui est ce qui est attendu. Avec votre code d'origine, je viens d'obtenir des valeurs aléatoires comme vous l'avez fait.

Autres conseils

Un problème dans gcc entraînait l'alignement de attribut pour qu'il ne fonctionne pas avec les variables de pile. Il semble être corrigé avec le correctif lié ci-dessous. Le lien ci-dessous contient également un peu de discussion sur le problème.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660

J'ai essayé votre code ci-dessus avec deux versions différentes de gcc: 4.1.2 à partir d'un RedHat 5.7 et cela a échoué de la même manière que votre problème (les tableaux locaux n’étaient en aucun cas alignés sur des bornes 0x1000). J'ai ensuite essayé votre code avec gcc 4.4.6 sur RedHat 6.3, et cela a fonctionné sans faille (les tableaux locaux ont été alignés). Les gens de Myth TV avaient un problème similaire (que le correctif de gcc ci-dessus semblait réparer):

http://code.mythtv.org/trac/ticket/6535

Quoi qu'il en soit, il semble que vous ayez trouvé un bogue dans gcc, qui semble avoir été corrigé dans les versions ultérieures.

Les versions récentes de GCC (testées avec la version 4.5.2-8ubuntu4) semblent fonctionner correctement avec la matrice alignée correctement.

#include <stdio.h>

int main(void)
{
    float a[4] = { 1.0, 2.0, 3.0, 4.0 };
    float b[4] __attribute__((aligned(0x1000))) = { 1.0, 2.0, 3.0, 4.0 };
    float c[4] __attribute__((aligned(0x10000))) = { 1.0, 2.0, 3.0, 4.0 };

    printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]);
    printf("%p %p %p %p\n", &b[0], &b[1], &b[2], &b[3]);
    printf("%p %p %p %p\n", &c[0], &c[1], &c[2], &c[3]);
}

je reçois:

0x7ffffffefff0 0x7ffffffefff4 0x7ffffffefff8 0x7ffffffefffc
0x7ffffffef000 0x7ffffffef004 0x7ffffffef008 0x7ffffffef00c
0x7ffffffe0000 0x7ffffffe0004 0x7ffffffe0008 0x7ffffffe000c

L’alignement n’est pas efficace pour tous les types. Vous devriez envisager d'utiliser une structure pour voir les attributs en action:

#include <stdio.h>

struct my_float {
        float number;
}  __attribute__((aligned(0x1000)));

struct my_float a[4] = { {1.0}, {2.0}, {3.0}, {4.0} };

int
main(void)
{
        printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]);
}

Ensuite, vous lirez:

0x603000 0x604000 0x605000 0x606000

Quel est ce à quoi vous vous attendiez?

Modifier: Poussé par @yzap et après le commentaire @Caleb Case, le problème initial est dû à la version de GCC uniquement . J'ai vérifié GCC 3.4.6 vs GCC 4.4.1 avec le code source du demandeur:

$ ./test_orig-3.4.6
0x7fffe217d200 0x7fffe217d204 0x7fffe217d208 0x7fffe217d20c
$ ./test_orig-4.4.1
0x7fff81db9000 0x7fff81db9004 0x7fff81db9008 0x7fff81db900c

Il est maintenant évident que les anciennes versions de GCC (quelque part avant la version 4.4.1) présentent des pathologies d'alignement.

Note 1: Le code que je propose ne répond pas à la question que j'avais comprise comme "alignant chaque champ du tableau".

Note 2: Le fait de placer un [] non statique dans main () et de le compiler avec GCC 3.4.6 rompt la directive d’alignement du tableau de struct, tout en maintenant une distance de 0x1000 entre les structs ... toujours aussi mauvaise! (voir la réponse @zifre pour des solutions de contournement)

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