私は、コンパイラがマシンコードを生成する方法、具体的にはGCCがどのようにスタックを扱うのかを深く理解しようとしています。そうすることで、シンプルなCプログラムを作成し、アセンブリに組み込み、結果を理解するために最善を尽くしています。ここでは簡単なプログラムだと、それが生成する出力:スタック割り当て、パディング、アラインメント
asmtest.c
を:
void main() {
char buffer[5];
}
asmtest.s
:24のバイトは、スタック用に割り当てられている理由
pushl %ebp
movl %esp, %ebp
subl $24, %esp
leave
ret
私には不可解だ何があります。私は、プロセッサがどのようにメモリをアドレス指定するかにより、スタックは4の増分で割り振られなければならないことを知っていますが、この場合、スタックポインタを24ではなく8バイトだけ移動する必要があります。バイトはスタック・ポインタを40バイト移動させ、スタック・ポインタを移動させるバッファは一切ありません。1〜16バイトのバッファが移動しますESP
24バイト。
は今8バイトと仮定すると、必要な定数(それがために何が必要か?)で、これは我々が16バイトのチャンクで割り当てていることを意味しています。コンパイラがなぜこのように整列するのでしょうか?私はx86_64プロセッサを使用していますが、64ビットワードでも8バイトのアライメントしか必要ありません。なぜ矛盾?参考のため
は、私は、GCC 4.0.1と10.5を実行しているMacでこれをコンパイルすることだし、何の最適化が有効になっていません。
"push%ebp"は8バイト減少しましたか?プラスretの8バイトは、すでに16バイトで整列されているはずです。なぜこの用量のコンパイラがこの8バイトを必要とするのでしょうか? –
ああ、私はそれを得た。これは32ビットのマシンです。ごめんなさい。これはretでなければなりません4バイト+ ebp 4バイト+アライメントされた8バイト+バッファ16 –
現在のバージョンのi386とx86-64 System V ABIは16Bスタックアラインメント( 'call'命令の前)を必要とするので、関数は仮定できますそれ。歴史的に、i386 ABIは4Bアライメントしか必要としませんでした。 (ABIドキュメントへのリンクはhttps://stackoverflow.com/tags/x86/infoを参照)。 GCCは、他の関数を呼び出せないリーフ関数でも '%esp'を整列させたままにします。スペースを確保しなければならない時に、ここで起こっていることです。 –