4

SSE計算を行うC関数があります。GCCでコンパイルすると、次のコードが得られます

/* Start of function */
mov    (%rdi),%rax
movslq %ecx,%rcx
...
mov    0x8(%rdi),%rax
pxor   %xmm12,%xmm3
movaps %xmm0,-0x28(%rsp)
movaps %xmm6,%xmm1
...
movaps 0x50(%rax,%rcx,1),%xmm2
movaps 0x60(%rax,%rcx,1),%xmm15
pxor   %xmm2,%xmm0
pxor   %xmm2,%xmm6
movaps -0x28(%rsp),%xmm2
pxor   %xmm15,%xmm5
pxor   %xmm15,%xmm2
movaps 0x70(%rax,%rcx,1),%xmm15
movaps (%rax,%rcx,1),%xmm11
mov    0x10(%rdi),%rax
movaps %xmm15,-0x18(%rsp)
pxor   %xmm11,%xmm4
pxor   %xmm12,%xmm11
pxor   %xmm15,%xmm12

命令を見てmovapsください-それはスタックトップを介したメモリへのアクセスです:

movaps %xmm15,-0x18(%rsp)

未定義メモリへのアクセスではないですか?そして、なぜ GCC はそのような間違ったコードを生成したのでしょうか?

4

1 に答える 1

7

アセンブリ レベルで「未定義のメモリ」などというものはありません。gcc は、動作が期待どおりである限り、適切と思われる方法でスタックにアクセスするコードを自由に発行できます。

なぜこれが起こっているのかについての私の推測は、これがスタックポインタを調整しても無駄なリーフ関数であるということです。アセンブリの指示を調べて、それを確認することができcallます。(C ソースを検査することもできますが、インライン化すると信頼性が少し低下する可能性があります。)

この種の策略は、x86-64 を含む特定のプラットフォームの ABI によって明示的に許可されています。AMD64 ABI ドキュメントから:

%rsp が指す場所を超える 128 バイトの領域は、予約されていると見なされ、シグナルまたは割り込みハンドラによって変更されません。したがって、関数は、関数呼び出し間で必要とされない一時データのためにこの領域を使用する場合があります。特に、リーフ関数は、プロローグとエピローグでスタック ポインターを調整するのではなく、スタック フレーム全体にこの領域を使用する場合があります。このエリアはレッドゾーンとして知られています。

このブログ投稿は、このテーマに関する興味深い読み物になるかもしれません。

于 2013-12-18T16:32:28.483 に答える