4

コンパイルされた (およびリンクされた) バイナリの関数が、C ファイルに記述されている順序で表示されるという C 標準の要件はありますか?

以下の例では、コンパイラは関数を削除/インライン化しておらず、それらはすべてバイナリに存在すると仮定してください。問題は、コンパイラが空の関数で何をするかではなく、関数の順序についてです。

たとえば、example.c をコンパイルすると、次のようになります。

void bar() {  }
void foo() {  bar();  }
int main() {   foo();  }

出力ファイルのfoo後に続くと確信できますか?bar

4

4 に答える 4

5

いいえ、C 標準にはそのような要件はありません。コンパイルとリンケージに関しては、extern リンケージや静的リンケージなど、関数の特定のプロパティのみが明示的に言及されていますが、これらもほとんど実装に依存しない方法で記述されています。これまでのところ、実行可能ファイル内のシンボルの順序について期待を課す条項は (私の知る限り) どの標準文書にもありません。

于 2013-01-01T20:18:49.770 に答える
2

言語にはこれに関する規則はありません。通常、それらはコードを見て期待する順序で表示されますが、コンパイラが関数のスタックを構築できず、完全に逆の順序で出力できないということは何もありません-確かに、呼び出されない関数同様に、インライン化されていて外部参照が不要であるとコンパイラが判断できる関数は、元の形式で削除できます。

関数がどこにあるかを調べることができますchar *ptr = (char *)bar;

編集:関数のアドレスを取得することで、関数のインライン化を変更できることに注意してください。これが、「通常の状況で」コンパイラが何をするかを判断する良い方法であるとは思わないでください。

于 2013-01-01T20:16:29.687 に答える
1

コンパイラ スイッチだけでこれを制御することはできません。2 段階のプロセスが必要です。ここでは ELF (UN*X オブジェクト ファイル形式) の例を示していますが、Windows PE オブジェクトの場合と同様に行うことができます。

  1. コード配置を厳密に制御する必要がある関数に対して、個別の/特定のオブジェクト ファイルELF セクションを生成するようにコンパイラに指示します。これは、GCC では、関数属性またはコマンド ライン スイッチを介して行うことができます。
    達成したい配置のタイプに応じて、GCC の関数属性 ( hotcold、...) の一部はすでに必要なことを行っている場合がありますが、そうでない場合は、特定の順序付け/特定の場所が絶対に必要です。
  2. 入力セクションを特定の方法で順序付け/再配置/マージ/配置するようにリンカに指示します。

実際のコード/データの配置はリンク時に発生します。リンカーは、結果のターゲット「複合オブジェクト」、つまり結果の実行可能ファイル/ライブラリ内の「構成オブジェクト」(ソース オブジェクトの ELF セクション) のオブジェクト コードの配置を制御できます。これは、リンカー スクリプトによって行われます。リンカーは、カスタムリンカー スクリプトを使用して指示された場合、入力セクションをユーザー指定の場所/ユーザー指定の順序で出力オブジェクトに配置します。リンカー スクリプトについては、 GNU binutils (ld) のマニュアルを参照してください。

結果として (リンカーが実際に出力のどこに入力のさまざまな部分を配置するかを反映して)、リンカー Mapfileの生成を要求できます。コードの配置を厳密に制御するために非デフォルト/カスタム リンカー スクリプトを使用した場合は、リンカーにそのように指示する必要があります。それ以外の場合、リンカのデフォルトを使用した場合、マップファイルは特定のオーバーライドなしで何が行われたかを通知します-それはあなたが望むものかもしれませんし、そうでないかもしれませんが、少なくともチェックする方法です.

于 2013-02-26T12:55:30.697 に答える
0

そのような要件はありません。ただし、あなたの例では、bar() が foo() の後に来た場合、foo は bar() を整数を返す未定義の関数と見なします。

于 2013-01-01T20:17:56.477 に答える