2009-05-08 6 views
84

tengo el siguiente código:¿Las variables de la pila están alineadas por 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]); 
} 

y yo tenemos el siguiente resultado:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

Por qué la dirección de a[0] no es un múltiplo de 0x1000?

¿Qué exactamente __attribute__((aligned(x))) hace? He entendido mal this explicación?

Estoy usando gcc 4.1.2.

Respuesta

94

Creo que el problema es que su matriz está en la pila. Debido a que el puntero de pila puede ser cualquier cosa cuando se inicia la función, no hay forma de alinear la matriz sin asignar mucho más de lo que necesita y ajustarlo. Si mueve la matriz de la función a una variable global, debería funcionar. La otra cosa que podrías hacer es mantenerlo como una variable local (que es algo muy bueno), pero hazlo static. Esto evitará que se almacene en la pila. Tenga en cuenta que estas dos formas no son seguras para subprocesos ni seguridad de recursión, ya que solo habrá una copia de la matriz.

Con este código:

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

me sale esto:

0x804c000 0x804c004 0x804c008 0x804c00c 

que es lo que se espera. Con su código original, obtengo valores aleatorios como los que hizo.

+11

+1 respuesta correcta. Una solución alternativa es hacer la matriz local estática. La alineación en la pila siempre es un problema y es mejor acostumbrarse a evitarla. –

+0

Oh, sí, no pensé en hacerlo estático. Esa es una buena idea, ya que evita las colisiones de nombres. Editaré mi respuesta. – Zifre

+2

Tenga en cuenta que al ser estático también lo hace no reentrante y no es seguro para subprocesos. – ArchaeaSoftware

9

La alineación no es efectiva para todos los tipos. Usted debe considerar el uso de una estructura para ver los atributos de la acción:

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

Y entonces, usted leerá:

0x603000 0x604000 0x605000 0x606000 

¿Qué es lo que estabas esperando.

Editar: Empujado por @yzap y comentario siguiente @Caleb caso, el problema inicial se debe a GCC versión única. He comprobado en GCC 3.4.6 vs GCC 4.4.1 con el código fuente del solicitante:

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

Ahora es obvio que las versiones anteriores del CCG (en algún lugar antes 4.4.1) muestra patologías de alineación.

Nota 1: Mi código propuesto no responde la pregunta que entendí como "alinear cada campo de la matriz".

Nota 2: Traer no estático a [] dentro de main() y compilar con GCC 3.4.6 rompe la directiva de alineación de la matriz de struct pero mantiene la distancia 0x1000 entre las estructuras ... ¡sigue siendo malo! (Consulte la respuesta de @zifre para las soluciones)

+1

Respondido por zifre, no es el tipo, sino el hecho de que lo hizo estático en su versión. – ysap

+0

@ysap, fue tanto la versión de GCC como la definición global lo que hizo que funcionara. Gracias por tu comentario! Edité la respuesta para arreglarlo. :) – levif

13

Los últimos GCC (probados con 4.5.2-8ubuntu4) parecen funcionar como se esperaba con la matriz alineada correctamente.

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

me sale:

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

Esto es un poco sorprendente, considerando que las matrices están asignadas en la pila, ¿significa que la pila ahora está llena de agujeros? – ysap

+0

O su pila está alineada con 16 bytes. – user7116

38

Hubo un error en gcc que causó atributo alineado a no trabajar con variables de pila. Parece que se corrigió con el parche vinculado a continuación. El siguiente enlace también contiene bastante debate sobre el problema.

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

me han tratado el código anterior con dos versiones diferentes de gcc 4.1.2: a partir de un cuadro de RedHat 5.7 , y no de forma similar a su problema (las matrices locales WRE de ninguna manera alineada sobre 0x1000 byte boundaies). Luego probé tu código con gcc 4.4.6 en RedHat 6.3, y funcionó sin problemas (las matrices locales estaban alineadas). La gente de televisión Mito tenían un problema similar (gcc que el parche anterior parecía fijar):

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

De todos modos, parece que ha encontrado un fallo en gcc, que parece estar fijo en versiones posteriores.

+3

De acuerdo con el error enlazado gcc 4.6 fue la primera versión con este problema completamente corregido para todas las arquitecturas. – textshell

Cuestiones relacionadas