これはすべて、IntelプラットフォームのBP / EBP/RBPレジスタに関するものです。このレジスタのデフォルトはスタックセグメントです(スタックセグメントにアクセスするために特別なプレフィックスは必要ありません)。
EBPは、スタック内のデータ構造、変数、および動的に割り当てられたワークスペースにアクセスするためのレジスターの最良の選択です。EBPは、現在のTOSではなく、スタック上の固定点を基準にしてスタック上の要素にアクセスするためによく使用されます。これは通常、現在のプロシージャ用に確立された現在のスタックフレームのベースアドレスを識別します。オフセット計算でEBPがベースレジスタとして使用される場合、オフセットは現在のスタックセグメント(つまり、SSによって現在選択されているセグメント)で自動的に計算されます。SSを明示的に指定する必要がないため、このような場合の命令エンコーディングはより効率的です。EBPを使用して、他のセグメントレジスタを介してアドレス指定可能なセグメントにインデックスを付けることもできます。
(ソース-http://css.csail.mit.edu/6.858/2017/readings/i386/s02_03.htm)
ほとんどの32ビットプラットフォームでは、データセグメントとスタックセグメントが同じであるため、このEBP/RBPとスタックの関連付けは問題ではなくなりました。64ビットプラットフォームでも同様です。2003年にAMDによって導入されたx86-64アーキテクチャは、64ビットモードでのセグメンテーションのサポートを大幅に廃止しました。4つのセグメントレジスタ:CS、SS、DS、およびESは強制的に0になります。 。x8632ビットおよび64ビットプラットフォームのこれらの状況は、基本的に、メモリにアクセスするプロセッサ命令でEBP/RBPレジスタをプレフィックスなしで使用できることを意味します。
したがって、あなたが書いたコンパイラオプションを使用すると、BP / EBP / RBPを他の手段、たとえばローカル変数を保持するために使用できます。
「これにより、フレームポインタの保存、設定、および復元の手順が回避されます」とは、各関数のエントリで次のコードを回避することを意味します。
push ebp
mov ebp, esp
または、enter
Intel80286および80386プロセッサで非常に役立つ命令。
また、関数が戻る前に、次のコードが使用されます。
mov esp, ebp
pop ebp
またはleave
指示。
デバッグツールは、スタックデータをスキャンし、これらのプッシュされたEBPレジスタデータを使用して、検索中にcall sites
、つまり、関数の名前と引数を階層的に呼び出された順序で表示する場合があります。
プログラマーは、スタックフレームについて、広義ではなく(スタック内の単一のエンティティであり、1つの関数呼び出しのみを処理し、リターンアドレス、引数、およびローカル変数を保持する)、狭義の質問をする場合がありますstack frames
。コンパイラオプションのコンテキスト。コンパイラーの観点からは、スタックフレームは、ルーチンの開始コードと終了コードにすぎず、アンカーをスタックにプッシュします。これは、デバッグや例外処理にも使用できます。デバッグツールは、スタックデータをスキャンし、これらのアンカーを使用してバックトレースを行いcall sites
、スタック内に配置します。つまり、関数の名前を階層的に呼び出されたのと同じ順序で表示します。
そのため、コンパイラーは、コンパイラー・オプションの観点からスタック・フレームが何であるかを理解することが重要です。コンパイラーは、このコードを生成するかどうかを制御できるからです。
場合によっては、スタックフレーム(ルーチンの開始コードと終了コード)をコンパイラーが省略でき、変数は便利なベースポインター(BP /)ではなくスタックポインター(SP / ESP / RSP)を介して直接アクセスされます。 ESP / RSP)。コンパイラが一部の関数のスタックフレームを省略するための条件は異なる場合があります。たとえば、次のようになります。(1)関数がリーフ関数(つまり、他の関数を呼び出さないエンドエンティティ)。(2)例外は使用されません。(3)スタック上の発信パラメーターを使用してルーチンが呼び出されることはありません。(4)関数にはパラメーターがありません。
スタックフレーム(ルーチンの開始コードと終了コード)を省略すると、コードをより小さく、より高速にすることができます。それでも、スタックのデータをバックトレースしてプログラマーに表示するデバッガーの機能に悪影響を与える可能性もあります。これらは、コンパイラがスタックフレームの開始コードと終了コードを関数に与えるために関数が満たす必要がある条件を決定するコンパイラオプションです。たとえば、コンパイラには、次の場合に関数にそのような開始コードと終了コードを追加するオプションがあります:(a)常に、(b)決して、(c)必要な場合(条件を指定)。
一般性から特殊性に戻る:-fomit-frame-pointer
GCCコンパイラオプションを使用する場合、ルーチンの開始コードと終了コードの両方、および追加のレジスタを使用することで勝つことができます(デフォルトでそれ自体または他のオプションによって暗黙的にオンになっている場合を除く)。この場合、EBP / RBPレジスタを使用することによるゲインの恩恵をすでに受けており、このオプションがすでに暗黙的にオンになっている場合は、このオプションを明示的に指定しても追加のゲインは得られません)。ただし、16ビットおよび32ビットモードでは、BPレジスタにはAXのように8ビット部分(ALおよびAH)へのアクセスを提供する機能がないことに注意してください。
このオプションは、コンパイラがEBPを最適化の汎用レジスタとして使用できるようにするだけでなく、スタックフレームの終了コードとエントリコードの生成を防ぎます。これにより、デバッグが複雑になります。そのため、GCCのドキュメントには明示的に記載されています(通常は太字で強調されています)。スタイル)このオプションを有効にすると、一部のマシンでデバッグが不可能になります。
-fomit-frame-pointer
また、デバッグまたは最適化に関連する他のコンパイラオプションによって、オプションが暗黙的にオンまたはオフになる場合があることにも注意してください。
-fomit-frame-pointer
他のオプションがx86プラットフォームにどのように影響するかについての公式情報はgcc.gnu.orgで見つかりませんでした、https: //gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html次のことだけを述べています。
-Oは、デバッグに干渉しないマシンで-fomit-frame-pointerもオンにします。
したがって、x86プラットフォームで単一の「-O」オプションを使用してコンパイルした場合にオンになるかどうかは、ドキュメント自体からは明らかではありません。-fomit-frame-pointer
経験的にテストされる可能性がありますが、この場合、GCC開発者は、将来このオプションの動作を予告なしに変更しないというコミットメントはありません。
ただし、Peter Cordes-fomit-frame-pointer
はコメントで、x86-16プラットフォームとx86-32/64プラットフォームのデフォルト設定に違いがあることを指摘しています。
このオプション– –は、GCCだけでなく、IntelC++コンパイラ15.0-fomit-frame-pointer
にも関連しています。
インテル®コンパイラーの場合、このオプションにはエイリアスがあり/Oy
ます。
Intelがそれについて書いたことは次のとおりです。
これらのオプションは、EBPが最適化の汎用レジスタとして使用されるかどうかを決定します。オプション-fomit-frame-pointerおよび/Oyは、この使用を許可します。オプション-fno-omit-frame-pointerおよび/Oy-はそれを許可しません。
一部のデバッガーは、EBPがスタックフレームポインターとして使用されることを想定しており、そうでない場合はスタックバックトレースを生成できません。-fno-omit-frame-pointerおよび/Oy-オプションは、デバッガーが次のことを行わなくてもスタックバックトレースを生成できるように、すべての関数のスタックフレームポインターとしてEBPを維持および使用するコードを生成するようにコンパイラーに指示します。
-fno-omit-frame-pointerの場合:-O0で最適化をオフにする/ Oy-の場合:/ O1、/ O2、または/ O3の最適化をオフにするオプション-を指定すると、-fno-omit-frame-pointerオプションが設定されます。 O0または-gオプション。-fomit-frame-pointerオプションは、オプション-O1、-O2、または-O3を指定したときに設定されます。
/ Oyオプションは、/ O1、/ O2、または/O3オプションを指定するときに設定されます。オプション/Oy-は、/Odオプションを指定するときに設定されます。
-fno-omit-frame-pointerまたは/Oy-オプションを使用すると、使用可能な汎用レジスターの数が1つ減り、コードの効率がわずかに低下する可能性があります。
注Linux*システムの場合:現在、GCC3.2の例外処理に問題があります。したがって、GCC3.2がC++用にインストールされ、例外処理がオンになっている場合(デフォルト)、インテル®コンパイラーはこのオプションを無視します。
上記の引用は、GCCではなくIntel C++15コンパイラにのみ関連することに注意してください。