スタック変数は GCC __attribute__((aligned(x))) によって整列されていますか?

問題は、配列がスタック上にあり、コンパイラが古すぎてオーバーアラインされたスタック変数をサポートできないことだと思います。 GCC 4.6 以降ではそのバグが修正されました。

C11/C++11 alignas(64) float a[4]; 2 の累乗のアライメントでのみ機能します。
GNU C __attribute__((aligned(x))) もそうです

(C11 では #include <stdalign.h> #define alignas _Alignas の場合 :cppref).

しかし、4k ページ境界までの非常に大きな位置合わせの場合、スタックに配置したくない場合があります。

関数の開始時にはスタック ポインターは何でもよいため、必要以上に多くを割り当てて調整しない限り、配列を整列させる方法はありません。 (コンパイラは and rsp, -4096 または同等であり、割り当てられた 0 ~ 4088 バイトのいずれも使用しません。そのスペースが十分に大きいかどうかで分岐することは可能ですが、配列または他のローカルのサイズよりもはるかに大きい巨大なアラインメントは通常のケースではないため、実行されません。)

配列を関数からグローバル変数に移動すると、機能するはずです。他にできることは、それをローカル変数として保持することです (これは非常に良いことです) が、static にします。 .これにより、スタックに格納されなくなります。配列のコピーは 1 つしかないため、これらの方法はどちらもスレッドセーフまたは再帰セーフではないことに注意してください。

このコードで:

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

私はこれを取得します:

0x804c000 0x804c004 0x804c008 0x804c00c

これは期待されるものです。元のコードでは、あなたと同じようにランダムな値を取得します.


attribute を引き起こす gcc のバグがありました スタック変数で動作しないように調整されています。以下にリンクされているパッチで修正されているようです。以下のリンクにも、この問題に関するかなりの議論が含まれています。

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

上記のコードを 2 つの異なるバージョンの gcc:RedHat 5.7box の 4.1.2 で試してみましたが、問題と同様に失敗しました (ローカル配列は 0x1000 バイト境界に整列していません)。次に、RedHat 6.3 で gcc 4.4.6 を使用してコードを試してみましたが、問題なく動作しました (ローカル配列は調整されていました)。 Myth TV 関係者にも同様の問題がありました (上記の gcc パッチで修正されたようです):

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

いずれにせよ、gcc にバグが見つかったようです。このバグは後のバージョンで修正されているようです。


最近の GCC (4.5.2-8ubuntu4 でテスト済み) は、配列が適切に配置されているため、期待どおりに動作しているようです。

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

私は得る:

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