6

「スタックアラインメント」とは何かで説明されているように、スタックアラインメントがどのように機能するかを理解しようとしていますか?しかし、私は前述の振る舞いを示すための小さな例を得るのに苦労しています。関数fooのスタック割り当てを調べています。

void foo() {
    int a = 0;
    char b[16];
    b[0] = 'a';
}

ソースファイルをコンパイルしましたgcc -ggdb example.c -o example.out(つまり、コンパイラフラグなしで)。gdbからのアセンブラダンプは次のようになります。

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x20,%esp
0x0804839a <+6>:    movl   $0x0,-0x4(%ebp)
0x080483a1 <+13>:   movb   $0x61,-0x14(%ebp)
0x080483a5 <+17>:   leave  
0x080483a6 <+18>:   ret    
End of assembler dump.

私のスタックは16バイトのチャンクに割り当てられています(これを他のいくつかのテストで検証しました)。ここでのアセンブラダンプによると、(16 <4 + 16 <32)のため、32バイトが割り当てられていますが、最初の16バイトに整数'a'が割り当てられ、次の16バイトに文字配列が割り当てられると予想しました。 (間に12バイトのスペースを残します)。しかし、整数配列と文字配列の両方に20バイトの連続したチャンクが割り当てられているようです。これは、上記で説明したように非効率的です。誰かが私がここで欠けているものを説明できますか?

編集:私は私のスタックが以下のようなプログラムで16バイトのチャンクに割り当てられているという結論に達しました:

void foo() {
    char a[1];
}

そして、対応するアセンブラダンプ:

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x10,%esp
0x0804839a <+6>:    leave  
0x0804839b <+7>:    ret    
End of assembler dump.

サイズ1の文字配列(1バイトのみが必要)のスタックに16バイトが割り当てられていることがわかります。配列のサイズを最大16まで増やすことができ、アセンブラーダンプは同じままですが、17の場合、スタックに32バイトが割り当てられます。私はそのようなサンプルをたくさん実行しましたが、結果は同じです。スタックメモリは16バイトのチャンクで割り当てられます。同様のトピックがスタックの割り当て、パディング、および配置で説明されていますが、私がもっと知りたいのは、私の例では配置が効果がない理由です。

4

5 に答える 5

5

すべてのスタック変数を個別に16バイト境界に揃える必要がないという事実を見逃していると思います。

于 2011-01-27T14:28:45.560 に答える
0

通常のルールでは、変数は32ビット境界に割り当てられます。16バイトに特別な意味があると思う理由がわかりません。

于 2011-01-27T14:29:11.097 に答える
0

特定のスタックアラインメントのようなことについて聞いたことがありません。CPUにアライメント要件がある場合、スタックまたは他の場所に格納されているかどうかに関係なく、すべての種類のデータメモリでアライメントが実行されます。これは、16、32、または64ビットのデータが続く偶数アドレスで開始されます。

16バイトは、おそらくある種のオンチップキャッシュメモリの最適化である可能性がありますが、それは私には少し遠いように思えます。

于 2011-01-27T14:54:18.027 に答える
0

良い例は、これを構造物で見ることです。

struct a{
    int a;
    char b;
    int c;
} a;

32ビットシステムでは、これを個別に取得すると4 + 1+4バイトになります。

構造体とそのメンバーが整列しているため、「char b」は4バイトになり、これは12バイトになります。

struct b{
    int a;
    char b;
    int c;
} __attribute__((__packed__)) b;

packed属性を使用すると、最小サイズを維持するように強制できます。したがって、この構造は9バイトです。

これも確認できますhttp://sig9.com/articles/gcc-packed-structures

お役に立てば幸いです。

于 2011-01-27T15:51:54.170 に答える
0

pahole http://packages.debian.org/lenny/dwarvesというツールを使用して、データ構造に追加のメモリがどのように割り当てられているかを確認できます。それはあなたのプログラムのすべての穴をあなたに示します:あなたがそれを合計した場合のあなたのデータのサイズとあなたのスタックに割り当てられた実際のサイズ

于 2011-12-17T14:12:05.133 に答える