5

空の C 関数をコンパイルすると

void nothing(void)
{
}

MacOS でgcc -O2 -S(および)を使用すると、以下が生成されます。clang

_nothing:
    pushq   %rbp
    movq    %rsp, %rbp
    popq    %rbp
    ret

gcc以外のすべてを削除しないのはなぜretですか? 本当に何かをしない限り、簡単に最適化できるように思えます (私にはそうではないようです)。このパターン (最初にプッシュ/ムーブ、最後にポップ) は、使用されていない他の空でない関数にも見られますrbp

最近のgcc (4.4.5)を使用しているLinuxでは、

nothing:
    rep
    ret

なぜrepですか?rep空でない関数には がありません。

4

4 に答える 4

3

なぜ担当者ですか?

理由は、このブログ投稿で説明されています。つまり、シングルバイトret命令に直接ジャンプすると、一部の AMD プロセッサで分岐予測が台無しになります。nopまた、 の前にを追加するのではなくret、無意味なプレフィックス バイトを追加して、命令デコードの帯域幅を節約しました。

空でない関数には担当者がありません。

私がリンクしたブログ投稿から引用すると、「[ ] は、条件付き ( ) または無条件 ( )のいずれかの種類のブランチのターゲットである場合rep ret、単純なものよりも優先されます」retjne/je/...jmp/call/... .
空の関数の場合、 はretの直接のターゲットになりcallます。空でない関数では、そうではありません。

gcc が ret 以外のすべてを削除しないのはなぜですか?

を指定した場合でも、一部のコンパイラはフレーム ポインター コードを省略しない可能性があります-O2。少なくとも gcc では、-fomit-frame-pointerオプションを使用してコンパイラにそれらを省略するように明示的に指示できます。

于 2013-08-05T12:24:06.727 に答える
2

ここで説明されているように: http://support.amd.com/us/Processor_TechDocs/25112.PDFrep retでは、一部の amd64 プロセッサでは 1 バイトのリターンが誤って予測される可能性があるため、2 バイトのニアリターン命令 (すなわち) が使用されます。このようないくつかの状況で。

gcc の対象となるプロセッサをいじると、シングルバイトのret. -mtune=nocona私のために働いた。

于 2013-08-05T07:15:59.973 に答える
1

早い段階で、最後のコードはバグだと思います。ジョンファウンドが言うように。最初のコードは、すべての C コンパイラが関数内での _cdecl 呼び出し規則に常に従わなければならないためです (Intel では、申し訳ありませんが、AT&T 構文はわかりません)。

関数定義

_functionA:
push   rbp
mov    rbp, rsp
;Some function
pop    rbp
ret

呼び出し元で:

call _functionA
sub esp, 0 ; Maybe if it zero, some compiler can strip it

GCC が常に _cdecl 呼び出し規約に従うのはナンセンスです。つまり、コンパイラは高度なアセンブリ プログラマよりも賢くありません。したがって、常に _cdecl に従います。

于 2013-08-05T06:49:57.753 に答える
-3

つまり、いわゆる「最適化コンパイラ」でさえ、常に適切なマシン コードを生成するにはあまりにも馬鹿げているからです。

作成者が生成させたよりも優れたコードを生成することはできません。

空の関数がナンセンスである限り、彼らは単にそれを最適化したり、この非常に特殊なケースを検出したりすることさえしなかったのでしょう。

ただし、単一の「rep」プレフィックスはおそらくバグです。文字列命令なしで使用すると何もしませんが、新しい CPU では理論的には例外が発生する可能性があります。(そして私見はそうすべきです)

于 2013-08-05T06:32:19.063 に答える