2009-05-08 8 views
84

Ich habe den folgenden Code:Sind Stack-Variablen vom GCC __attribut __ ((aligned (x))) ausgerichtet?

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

Und ich folgende Ausgabe haben:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

Warum die Adresse a[0] nicht ein Vielfaches von 0x1000 ist?

Was genau funktioniert __attribute__((aligned(x)))? Ich missverstanden this Erklärung?

Ich benutze gcc 4.1.2.

Antwort

94

Ich glaube, das Problem ist, dass Ihr Array auf dem Stapel ist. Da der Stapelzeiger alles sein kann, wenn die Funktion startet, gibt es keine Möglichkeit, das Array auszurichten, ohne viel mehr zuzuweisen als nötig und anzupassen. Wenn Sie das Array aus der Funktion in eine globale Variable verschieben, sollte es funktionieren. Die andere Sache, die Sie tun könnten, ist, es als lokale Variable zu behalten (was eine sehr gute Sache ist), aber machen Sie es static. Dies verhindert, dass es auf dem Stapel gespeichert wird. Beachten Sie, dass diese beiden Methoden nicht threadsicher oder rekursiv sind, da nur eine Kopie des Arrays vorhanden ist.

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

ich dieses:

0x804c000 0x804c004 0x804c008 0x804c00c 

das ist, was erwartet wird. Mit deinem ursprünglichen Code erhalte ich zufällige Werte wie du.

+11

+1 richtige Antwort. Eine alternative Lösung besteht darin, das lokale Array statisch zu machen. Die Ausrichtung auf dem Stapel ist immer ein Problem, und es ist am besten, sich daran zu gewöhnen, es zu vermeiden. –

+0

Oh ja, ich habe nicht daran gedacht es statisch zu machen. Das ist eine gute Idee, da es Namenskollisionen verhindert. Ich werde meine Antwort bearbeiten. – Zifre

+2

Beachten Sie, dass es statisch ist und nicht einspringt und nicht threadsicher ist. – ArchaeaSoftware

9

Alignement ist nicht für alle Typen geeignet. Sie sollten mit einer Struktur, um zu sehen, die Attribute in Aktion betrachten:

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

Und dann werden Sie lesen:

0x603000 0x604000 0x605000 0x606000 

Das ist, was Sie erwartet hatten.

Edit: Gedrückt von @yzap und folgenden @Caleb Fall Kommentar, das ursprüngliche Problem ist aufgrund der GCC-Version nur. Ich habe auf GCC 3.4.6 vs GCC geprüft 4.4.1 mit dem Quellcode des Autors ist:

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

Es ist nun offensichtlich, dass ältere GCC-Versionen (irgendwo vor 4.4.1) Ausrichtung Pathologien zeigen.

Hinweis 1: Mein vorgeschlagener Code beantwortet nicht die Frage, die ich als "jedes Feld des Arrays ausrichten" verstanden habe.

Anmerkung 2: Bringt nicht-statische a [] innerhalb von main() und kompiliert mit GCC 3.4.6 bricht die Alignment-Direktive des Arrays von struct aber hält 0x1000 Abstand zwischen Strukturen ... immer noch schlecht! (siehe @zifer-Antwort für Problemumgehungen)

+1

Wie von zifre beantwortet, ist es nicht der Typ, sondern die Tatsache, dass Sie es in Ihrer Version statisch gemacht haben. – ysap

+0

@ysap, war es sowohl GCC-Version und globale Definition, die es funktioniert. Danke für deinen Kommentar! Ich habe die Antwort bearbeitet, um es zu beheben. :) – levif

13

Der letzte GCC (getestet mit 4.5.2-8ubuntu4) scheint erwartungsgemäß mit dem Array ordnungsgemäß zu funktionieren.

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

ich:

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

Das ist ein wenig überraschend, wenn man bedenkt, dass die Arrays im Stack verteilt sind - bedeutet das, dass der Stack nun voller Löcher ist? – ysap

+0

Oder sein Stapel ist 16-Byte ausgerichtet. – user7116

38

ein Fehler in gcc Es war das Attribut ausgerichtet verursachte nicht mit Stack-Variablen zu arbeiten. Es scheint mit dem unten verlinkten Patch behoben zu sein. Der Link unten enthält auch einige Diskussionen für das Problem.

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

Ich habe den Code oben mit zwei verschiedenen Versionen von gcc versucht: 4.1.2 von einer 5,7 RedHat-Box, und es scheiterte in ähnlicher Weise für Ihr Problem (den lokalen Arrays wre in keine Weise auf 0x1000 ausgerichtet Byte-Grenzen). Ich habe dann Ihren Code mit gcc 4.4.6 auf RedHat 6.3 versucht, und es funktionierte einwandfrei (die lokalen Arrays wurden ausgerichtet). Die Myth TV Leute hatten ein ähnliches Problem (das der gcc-Patch über zu beheben schien):

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

Wie auch immer, es sieht aus wie Sie einen Fehler in gcc gefunden, die in späteren Versionen behoben zu sein scheint.

+3

Laut dem verlinkten Bug war gcc 4.6 das erste Release mit diesem Problem, das für alle Architekturen vollständig behoben wurde. – textshell

Verwandte Themen