¿Las variables de pila están alineadas por el atributo GCC ((aligned (x)))?


Tengo el siguiente código:

#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 tengo la siguiente salida:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac

¿por Qué la dirección de a[0] no es un múltiplo de 0x1000?

¿Qué hace exactamente __attribute__((aligned(x)))? ¿Malinterpreté esta explicación?

Estoy usando gcc 4.1.2.

4 answers

Creo que el problema es que su matriz está en la pila. Debido a que el puntero de pila podría ser cualquier cosa cuando se inicia la función, no hay manera de alinear la matriz sin asignar mucho más de lo que necesita y ajustarlo. Si mueve la matriz fuera de la función y a una variable global, debería funcionar. La otra cosa que podrías hacer es mantenerla como una variable local (lo cual es algo muy bueno), pero que sea static. Esto evitará que se almacene en la pila. Cuidado que ambos de estas formas no son seguras para subprocesos o recursivas, 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]);
}

Entiendo esto:

0x804c000 0x804c004 0x804c008 0x804c00c

Que es lo que se espera. Con tu código original, solo obtengo valores aleatorios como lo hiciste tú.

 95
Author: Zifre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-08 19:51:58

Hubo un error en gcc que causó que el atributo alineado no funcionara con variables de pila. Parece arreglarse con el parche vinculado a continuación. El siguiente enlace también contiene un poco de discusión para el problema también.

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

He probado el código anterior con dos versiones diferentes de gcc: 4.1.2 de un RedHat 5.7 cuadro, y falló de manera similar a su problema (los arrays locales wre de ninguna manera alineado en 0x1000 byte boundaies). Luego probé su código con gcc 4.4.6 en RedHat 6.3, y funcionó sin problemas (los arrays locales estaban alineados). La gente de Myth TV tenía un problema similar (que el parche de gcc anterior parecía arreglar):

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

De todos modos, parece que ha encontrado un error en gcc, que parece ser corregido en versiones posteriores.

 39
Author: rts1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-15 22:17:45

Los GCC recientes (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]);
}

Obtengo:

0x7ffffffefff0 0x7ffffffefff4 0x7ffffffefff8 0x7ffffffefffc
0x7ffffffef000 0x7ffffffef004 0x7ffffffef008 0x7ffffffef00c
0x7ffffffe0000 0x7ffffffe0004 0x7ffffffe0008 0x7ffffffe000c
 13
Author: Caleb Case,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-04 02:36:16

La alineación no es efectiva para todos los tipos. Deberías considerar usar una estructura para ver los atributos en 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 luego, leerás:

0x603000 0x604000 0x605000 0x606000

Que es lo que esperabas.

Editar: Empujado por @yzap y siguiendo el comentario del caso @Caleb, el problema inicial se debe a la versión de GCC solo. 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 más antiguas de GCC (en algún lugar antes de 4.4.1) muestra patologías de alineación.

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

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

 9
Author: levif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-23 00:01:24