6

コンパイラとその仕組みについて少し調べたところ、プロセスは多くの場合、プリプロセッサ、コンパイラ、アセンブラ、リンカーの 4 つのステップに分かれていることがわかりました。私がこれらのステップを思い描いた方​​法は、それぞれが独自の個別のプログラムであることでした。プリプロセッサプログラム、コンパイラプログラム、アセンブラプログラム、リンカプログラム。ただし、アセンブリ コードの作成とオブジェクト ファイルの生成のプロセスがすべてコンパイラ プログラムによって処理される場合と、そうでない場合があることがわかります。使用するコンテキストとプログラミング言語に大きく依存するようです。私の質問は、C++ ソース コードをマシン コードに変換するために、一般的な変換プロセスをどのように分割するかということです。

  1. プリプロセッサはコンパイラとは別のプログラムですか? それとも、そのプロセスは通常、コンパイラ プログラムの一部ですか?
  2. コンパイラは通常、何を担当しますか? アセンブリ コードを生成してからマシン コードに変換しますか?
  3. リンカーは、コンパイラの終了後に実行される独自の別のプログラムですか?

補足: 私の質問は他の C++ コンパイラ スレッドとは異なります。なぜなら、コンパイラがどのように機能するかだけでなく、リンクなどの他の特定のプロセスに独自の実行可能プログラムがあるかどうか、またはそれらが通常コンパイラ プログラムに組み込まれているかどうかを尋ねているからです。

4

1 に答える 1

4

最近のすべてのコンパイラ (少なくとも gcc と clang ですが、他は大きく異なるとは思いません) には、前処理とコンパイラが 1 つの実行可能ファイルとして含まれています。これは主に、コンパイラが適切なエラー メッセージを生成できるようにしたいためです [正しい行と列を指し、マクロが含まれている場合は、「マクロ FOO(x) から呼び出されました」と言うことができます]。 「re in」は、コンパイラーが前処理されたコードではなく、実際のソースコードを確認できる場合に簡単です。

通常、リンカは別のプログラムであり、アセンブラはインライン アセンブリ コードにのみ使用されます [通常、コンパイラの統合部分として]。私が最もよく知っているコンパイラ]。したがって、コンパイラから完全に形成されたオブジェクト ファイルが生成されます。

正しいオプションがある場合、リンカーが呼び出されますが、別の実行可能ファイルであり、オブジェクト ファイルをランタイム ライブラリと「メインの前に」開始コード (グローバル オブジェクトの構築など、および「 main を呼び出す準備をしています」)。これにより、実行可能ファイルが生成されます。

他のオプションを使用すると、コンパイラはオブジェクト ファイルのみを生成するか、シンボリック形式で生成されたマシン コードの逆アセンブリを生成します (-Sオプション)。

コード生成を担当するコンパイラのバックエンド部分は、通常、最適化とさまざまなコード変換を処理して最適化段階を支援します。たとえば、Clang + LLVM は、使用したかどうかに関係なく、「均一な」ループを生成しますwhileforまたはgotoループを作成します。

これにより、より高度な段階で多くの異なる形式のループを識別する必要がなくなり、プログラマーがループをどのように形成したかに関係なく、コンパイラーが「適切な」コードを生成できるようになります。[もちろん、十分に複雑にすると、コンパイラはおそらくループがどのように機能するかを完全には把握できず、最適化もうまくいきませんが、基本的な形式間の単純な変換では、関係なく同じ最終的なコード生成を行います。ソースがどのように見えるかの]。

于 2015-12-05T17:40:52.067 に答える