「スタックアラインメント」とは何かで説明されているように、スタックアラインメントがどのように機能するかを理解しようとしていますか?しかし、私は前述の振る舞いを示すための小さな例を得るのに苦労しています。関数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バイトのチャンクで割り当てられます。同様のトピックがスタックの割り当て、パディング、および配置で説明されていますが、私がもっと知りたいのは、私の例では配置が効果がない理由です。