2009-05-08 21 views
84

ho il seguente codice:Le variabili stack sono allineate con GCC __attribute __ ((aligned (x)))?

#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]); 
} 

e ho il seguente output:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

Perché l'indirizzo del a[0] non è un multiplo di 0x1000?

Che cosa fa esattamente __attribute__((aligned(x)))? Ho frainteso spiegazione this?

Sto utilizzando gcc 4.1.2.

risposta

94

Credo che il problema sia che la matrice è in pila. Poiché il puntatore dello stack può essere qualsiasi cosa all'avvio della funzione, non è possibile allineare l'array senza allocare molto più del necessario e regolarlo. Se si sposta la matrice fuori dalla funzione e in una variabile globale, dovrebbe funzionare. L'altra cosa che potresti fare è tenerla come variabile locale (che è una cosa molto buona), ma renderla static. Ciò impedirà che venga memorizzato nello stack. Fate attenzione che entrambi questi modi non sono sicuri per i thread o ricorsivi, poiché ci sarà solo una copia dell'array.

Con questo codice:

#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]); 
} 

ottengo questo:

0x804c000 0x804c004 0x804c008 0x804c00c 

che è quello che ci si aspetta. Con il tuo codice originale, ottengo solo valori casuali come hai fatto tu.

+11

+1 risposta corretta. Una soluzione alternativa consiste nel rendere statico l'array locale. L'allineamento in pila è sempre un problema ed è meglio prendere l'abitudine di evitarlo. –

+0

Oh sì, non pensavo di renderlo statico. Questa è una buona idea dal momento che previene le collisioni di nomi. Modificherò la mia risposta. – Zifre

+2

Nota che renderlo statico lo rende anche non rientranti e non thread-safe. – ArchaeaSoftware

9

L'allineamento non è valido per tutti i tipi. Si dovrebbe considerare l'utilizzo di una struttura per vedere gli attributi in azione:

#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]); 
} 

E poi, potrai leggere:

0x603000 0x604000 0x605000 0x606000 

che è quello che ti aspettavi.

Edit: Spinto dalla @yzap e commentare seguente @Caleb caso, il problema iniziale è dovuto al GCC versione solo. Ho controllato su GCC 3.4.6 vs GCC 4.4.1 con il codice sorgente del richiedente:

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

E 'ormai evidente che le versioni più vecchie di GCC (da qualche parte prima 4.4.1) mostra patologie di allineamento.

Nota 1: il mio codice proposto non risponde alla domanda che ho inteso come "allineamento di ogni campo dell'array".

Nota 2: l'inserimento di un [] in main() non statico con GCC 3.4.6 interrompe la direttiva di allineamento dell'array di struct ma mantiene 0x1000 la distanza tra le strutture ... ancora male! (vedi risposta @zifre per soluzioni alternative)

+1

Come risposta da zifre, non è il tipo, ma il fatto che l'hai reso statico nella tua versione. – ysap

+0

@ysap, è stata sia la versione GCC sia la definizione globale che ha funzionato. Grazie per il tuo commento! Ho modificato la risposta per risolverlo. :) – levif

13

Il GCC recente (testato con 4.5.2-8ubuntu4) sembra funzionare come previsto con allineamento dell'array corretto.

#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]); 
} 

ottengo:

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

Questo è un po 'sorprendente, considerando che gli array sono allocati nello stack - vuol dire che lo stack ora è pieno di buchi? – ysap

+0

Oppure il suo stack è allineato a 16 byte. – user7116

38

C'era un bug in gcc che ha causato attributo allineato a non funzionare con le variabili di stack. Sembra risolto con la patch collegata sotto. Il link sottostante contiene anche un bel po 'di discussioni per il problema.

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

ho cercato il tuo codice di cui sopra con due diverse versioni di gcc 4.1.2: da una scatola di RedHat 5.7 , ed è riuscito in modo simile al vostro problema (gli array locali WRE in alcun modo allineata a 0x1000 byte boundaies). Ho quindi provato il tuo codice con gcc 4.4.6 su RedHat 6.3, e ha funzionato alla perfezione (gli array locali erano allineati). La gente TV Mito ha avuto un problema simile (che la patch gcc sopra sembrava risolvere):

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

In ogni caso, sembra aver trovato un bug in gcc, che sembra essere fissato nelle versioni successive.

+3

In base al bug collegato gcc 4.6 è stata la prima versione con questo problema completamente risolto per tutte le architetture. – textshell

Problemi correlati