EBPフレームポインターレジスタの目的は何ですか?


94

私はアセンブリ言語の初心者ですが、コンパイラーによって生成されたx86コードは、EBP他の何かのためにレジスターを使用できるリリース/最適化モードでも、通常フレームポインターを保持していることに気づきました。

フレームポインターがコードのデバッグを容易にする理由、およびalloca()関数内で呼び出された場合に必要になる理由を理解しています。ただし、x86には非常に少数のレジスターがあり、そのうちの2つを使用してスタックフレームの場所を保持する場合、私には意味がありません。最適化されたリリースやリリースビルドでも、フレームポインターを省略することが悪い考えと見なされるのはなぜですか?


19
あなたはx86のは非常に少数のレジスタを持っていると思う場合は、6502 :)チェックする必要があります
Sedat Kapanoglu


1
C99 VLAもそれから利益を得ることができます。
Ciro Santilli郝海东冠状病六四事件法轮功


1
フレームポインターはスタックポインターを冗長にしませんか?。TL; DR:1.重要なスタックアライメント2.スタックの割り当て(alloca3.実行時の実装の容易さ:例外処理、サンドボックス、GC
Alexander Malakhov

回答:


102

フレームポインターは、ローカル変数または引数が単一の定数オフセットでどこにあるかをデバッガーが知ることができるようにする参照ポインターです。ESPの値は実行中に変化しますが、EBPは同じままなので、同じオフセットで同じ変数に到達することができます(たとえば、最初のパラメーターは常にEBP + 8になりますが、ESPオフセットは、 /物を飛び出る)

コンパイラがフレームポインタを破棄しないのはなぜですか?フレームポインターを使用すると、デバッガーはローカル変数と引数がEBPへの一定のオフセットであることが保証されているため、シンボルテーブルを使用している場所を特定できます。それ以外の場合、ローカル変数がコード内のどこにあるかを簡単に把握する方法はありません。

Gregが述べたように、EBPはスタックフレームの逆リンクリストを提供し、デバッガーが関数のスタックフレーム(ローカル変数+引数)のサイズを把握できるようにするため、デバッガーのスタックの巻き戻しにも役立ちます。

ほとんどのコンパイラは、デバッグを非常に困難にしますが、フレームポインタを省略するオプションを提供します。このオプションは、リリースコードであっても、グローバルに使用しないでください。ユーザーのクラッシュをいつデバッグする必要があるかはわかりません。


10
コンパイラはおそらくそれがESPに何をするか知っています。その他のポイントは有効ですが、+ 1
エリッカレン2009

8
最新のデバッガーは、でコンパイルされたコードでもスタックバックトレースを実行できます-fomit-frame-pointer。その設定は最近のgccのデフォルトです。
Peter Cordes、2015年

2
@SedatKapanoglu:データセクションは、必要な情報を記録:yosefk.com/blog/...
ピーター・コルド

3
@SedatKapanoglu:この.eh_frame_hdrセクションはランタイム例外にも使用されます。objdump -hLinuxシステムのほとんどのバイナリで(を使用して)見つかります/bin/bash。GNUの場合は572B、GNUの/bin/true場合は57kであるのに対し、は約16k ですffmpeg。生成を無効にするgccオプションがありますが、これは「通常の」データセクションであり、stripデフォルトで削除されるデバッグセクションではありません。そうしないと、デバッグシンボルを持たないライブラリ関数をバックトレースできません。そのセクションpush/mov/popは、置き換えられる命令よりも大きい場合がありますが、実行時のコストはほぼゼロです(たとえば、uopキャッシュ)。
Peter Cordes、2015年

3
「最初のパラメーターは常にEBP-4にある」などに関して:EBP + 8(x86)の最初のパラメーターではないですか?
Aydin K.

31

ちょうど良い答えに私の2セントを追加するだけです。

スタックフレームのチェーンを持つことは、優れた言語アーキテクチャの一部です。BPは、サブルーチンローカル変数が格納されている現在のフレームを指します。(ローカルは負のオフセットにあり、引数は正のオフセットにあります。)

完全に優れたレジスタが最適化で使用されないようにするという考えは、最適化が実際にいつ、どこで価値があるのか​​という疑問を投げかけます。

最適化は、1)関数を呼び出さない、2)プログラムカウンターがその時間のかなりの部分を費やす、および3)コンパイラーが実際に見るコード(つまり、非ライブラリ関数)でタイトなループでのみ価値があります。これは通常、特に大規模なシステムでは、コード全体のごく一部です。

他のコードは、サイクルを取り除くためにねじったり絞ったりすることができます。プログラムカウンターが実際にはそこにないため、それは単に問題になりません。

あなたはこれを聞かなかったと思いますが、私の経験では、パフォーマンスの問題の99%はコンパイラの最適化とはまったく関係がありません。彼らはオーバーデザインと関係があります。


@Mikeに感謝します。あなたの答えはとても役に立ちました。
sixtyfootersdude 2010

2
フレームポインタをなくすことで、関数呼び出しごとにいくつかの命令も節約できます。これは、それ自体が小さな最適化です。ところで、「質問をしてください」の使い方は正しくありません。あなたは「問題を提起する」という意味です。
オーグラ

@augurar:修正されました。ありがとう。私は少し文法に不満があります:)
Mike Dunlavey

3
@augurar言語が進化する:「質問を請う」は、「質問を上げる」という意味になりました。時代遅れの使用法のための規範主義者nitpickerであることは何も追加しません。
user3364825 2014

9

それは確かにコンパイラに依存します。EBPレジスターを汎用レジスターとして自由に使用するx86コンパイラーによって生成された最適化されたコードを見てきました。(ただし、どのコンパイラで気付いたかは覚えていません。)

コンパイラーは、例外処理中のスタックの巻き戻しを支援するためにEBPレジスターを維持することも選択できますが、これもまた、正確なコンパイラーの実装に依存します。


ほとんどのコンパイラでは-fomit-frame-pointer、最適化が有効になっているときにデフォルトで使用されます。(ABIが許可する場合)。GCC、clang、ICC、およびMSVCはすべて、32ビットWindowsをターゲットにしている場合でも、IIRCを実行します。ええ、スタック上のパラメーターを見つけるためにespレジスターよりもebpを使用する方が良いのはなぜですか?32ビットのWindowsでもフレームポインターを省略できることを示しています。32ビットのx86 Linuxは間違いなくできます。そしてもちろん、64ビットABIは最初からフレームポインターの省略を許可しています。
Peter Cordes

4

ただし、x86にはレジスタがほとんどありません

これは、オペコードがアドレス指定できるレジスタは8つだけという意味でのみ当てはまります。プロセッサ自体には実際にはそれよりも多くのレジスタがあり、レジスタの名前変更、パイプライン処理、投機的実行、およびその他のプロセッサの流行語を使用して、その制限を回避します。ウィキペディアには、x86プロセッサーがレジスターの制限を克服するために何ができるかについての適切な紹介段落があります:http : //en.wikipedia.org/wiki/X86#Current_implementations


1
元の質問は、生成されたコードに関するもので、オペコードで参照できるレジスタに厳密に制限されています。
ダロン

1
はい。しかし、このため、最適化されたビルドでフレームポインターを省略することは、今日ではそれほど重要ではありません。
マイケル

1
ただし、レジスタの名前の変更は、実際に利用可能なレジスタの数を増やすこととはまったく異なります。レジスタの名前変更が役に立たない状況はまだたくさんありますが、より「通常の」レジスタが役立つでしょう。
jalf

1

スタックフレームを使用することで、遠隔地にあるどのハードウェアでも信じられないほど安価になりました。安価なスタックフレームがある場合、レジスタをいくつか保存することはそれほど重要ではありません。高速スタックフレームとレジスタ数の増加はエンジニアリングのトレードオフであり、高速スタックフレームが勝ったと私は確信しています。

純正レジスターをいくら節約しますか?その価値はありますか?


より多くのレジスタは、命令のエンコーディングによって制限されます。x86-64は、REXプレフィックスバイトのビットを使用して、srcおよびdestレジスタの命令のレジスタ指定部分を3ビットから4ビットに拡張します。余裕がある場合、x86-64はおそらく32個のアーキテクチャレジスタに移動しますが、コンテキストスイッチの多くを保存/復元すると、増加し始めます。15は7からの大幅な増加ですが、31はほとんどの場合はるかに小さな改善です。(スタックポインターを汎用として数えません。)プッシュ/ポップを高速化することは、スタックフレームだけではありません。ただし、これは登録数とのトレードオフではありません。
Peter Cordes、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.