回答:
=====> COMPILATION PROCESS <======
|
|----> Input is Source file(.c)
|
V
+=================+
| |
| C Preprocessor |
| |
+=================+
|
| ---> Pure C file ( comd:cc -E <file.name> )
|
V
+=================+
| |
| Lexical Analyzer|
| |
+-----------------+
| |
| Syntax Analyzer |
| |
+-----------------+
| |
| Semantic Analyze|
| |
+-----------------+
| |
| Pre Optimization|
| |
+-----------------+
| |
| Code generation |
| |
+-----------------+
| |
| Post Optimize |
| |
+=================+
|
|---> Assembly code (comd: cc -S <file.name> )
|
V
+=================+
| |
| Assembler |
| |
+=================+
|
|---> Object file (.obj) (comd: cc -c <file.name>)
|
V
+=================+
| Linker |
| and |
| loader |
+=================+
|
|---> Executable (.Exe/a.out) (com:cc <file.name> )
|
V
Executable file(a.out)
Cの前処理は、コンパイルの最初のステップです。それは処理します:
#define
ステートメント。#include
ステートメント。ユニットの目的は、CソースファイルをPure Cコードファイルに変換することです。
ユニットには6つのステップがあります。
ソースファイル内の文字を組み合わせて「トークン」を形成します。トークンは、「スペース」、「タブ」、「改行」を含まない文字のセットです。したがって、このコンパイルの単位は「トークン化機構」とも呼ばれます。また、コメントを削除し、シンボルテーブルと再配置テーブルのエントリを生成します。
このユニットは、コードの構文をチェックします。例:
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
上記のコードでは、方程式のバランスが取れていないため、解析エラーが発生します。このユニットは、次のようにパーサーツリーを生成することにより、内部的にこれをチェックします。
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
したがって、このユニットはパーサーとも呼ばれます。
このユニットはステートメントの意味をチェックします。例:
{
int i;
int *p;
p = i;
-----
-----
-----
}
上記のコードは、「互換性のないタイプの割り当て」というエラーを生成します。
このユニットはCPUから独立しています。つまり、2種類の最適化があります。
このユニットは、次の形式でコードを最適化します。
例:
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
ここで、コンパイラーはコンパイル時に 'a'の値を認識しているため、if条件が常にtrueであることも認識しています。したがって、コードのelse部分が削除されます。
例:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = a + b + c;
/*
...
*/
}
次のように最適化できます。
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = x + c; // a + b is replaced by x
/*
...
*/
}
例:
{
int a;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
a = 10;
/*
...
*/
}
}
上記のコードで、 'a'がローカルでループで使用されていない場合は、次のように最適化できます。
{
int a;
a = 10;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
}
}
ここでは、コンパイラーがアセンブリー・コードを生成するため、使用頻度の高い変数がレジスターに保管されます。
ここで、最適化はCPUに依存します。コードに複数のジャンプがあるとすると、それらは次のように1つに変換されます。
-----
jmp:<addr1>
<addr1> jmp:<addr2>
-----
-----
コントロールは直接ジャンプします。
次に、最後のフェーズはリンクです(実行可能ファイルまたはライブラリを作成します)。実行可能ファイルを実行すると、必要なライブラリが読み込まれます。
ASCII表記:
[Source Code] ---> Compiler ---> [Object code] --*
|
[Source Code] ---> Compiler ---> [Object code] --*--> Linker --> [Executable] ---> Loader
| |
[Source Code] ---> Compiler ---> [Object code] --* |
| |
[Library file]--* V
[Running Executable in Memory]
これがもう少しお役に立てば幸いです。
まず、この図を見てください。
(img source->internet)
コードを作成してファイル(ソースコード)を保存し、
前処理:-名前が示すように、これはコンパイルの一部ではありません。これらは、実際のコンパイルの前に必要な前処理を行うようにコンパイラーに指示します。このフェーズは、テキスト置換、または#で示される特別なプリプロセッサディレクティブを解釈して呼び出すことができます。
コンパイル:-コンパイルは、ある言語で書かれたプログラムが別のターゲット言語に翻訳されるプロセスです。エラーがある場合、コンパイラーはそれらを検出して報告します。
アセンブル:-アセンブルコードはマシンコードに変換されます。アセンブラを特別なタイプのコンパイラと呼ぶことができます。
リンク:-これらのコードに他のソースファイルをリンクする必要がある場合は、リンカでリンクして実行可能ファイルにします。
その後に起こる多くのプロセスがあります。はい、あなたはそれがここのローダーの役割になると推測しました:
ローダー:-実行可能コードをメモリにロードします。プログラムとデータスタックが作成され、レジスタが初期化されます。
少し余分な情報:-http: //www.geeksforgeeks.org/memory-layout-of-c-program/、そこにメモリレイアウトがあります。
コンパイラ:高級言語プログラムを機械語プログラムに翻訳するプログラムです。コンパイラーはアセンブラーよりもインテリジェントです。あらゆる種類の制限、範囲、エラーなどをチェックします。しかし、そのプログラムの実行時間は長く、メモリの大部分を占めます。速度が遅い。なぜなら、コンパイラーはプログラム全体を調べてから、プログラム全体をマシンコードに変換するからです。コンパイラがコンピュータ上で実行され、同じコンピュータのマシンコードを生成する場合、それはセルフコンパイラまたは常駐コンパイラと呼ばれます。一方、コンパイラーがコンピューター上で実行され、他のコンピューター用のマシンコードを生成する場合、クロスコンパイラーと呼ばれます。
リンカー:高水準言語では、一部の組み込みヘッダーファイルまたはライブラリが保存されます。これらのライブラリは事前定義されており、プログラムの実行に不可欠な基本機能が含まれています。これらの関数は、リンカーと呼ばれるプログラムによってライブラリにリンクされます。リンカーが関数のライブラリを見つけられない場合、コンパイラーに通知し、コンパイラーはエラーを生成します。コンパイラーは、プログラムをコンパイルする最後のステップとしてリンカーを自動的に呼び出します。組み込みライブラリではなく、ユーザー定義関数をユーザー定義ライブラリにリンクします。通常、長いプログラムは、モジュールと呼ばれる小さなサブプログラムに分割されます。そして、これらのモジュールを組み合わせてプログラムを実行する必要があります。モジュールを組み合わせるプロセスは、リンカーによって行われます。
ローダー:ローダーは、プログラムのマシンコードをシステムメモリにロードするプログラムです。コンピューティングでは、ローダーはプログラムのロードを担当するオペレーティングシステムの一部です。これは、プログラムを開始するプロセスの重要な段階の1つです。これは、プログラムをメモリに配置し、実行する準備をするためです。プログラムをロードするには、実行可能ファイルの内容をメモリに読み込む必要があります。ロードが完了すると、オペレーティングシステムは、ロードされたプログラムコードに制御を渡すことによってプログラムを開始します。プログラムの読み込みをサポートするすべてのオペレーティングシステムにはローダーがあります。多くのオペレーティングシステムでは、ローダーはメモリに常駐しています。
ウィキペディアは良い答えを持つべきです、これが私の考えです:
*
*
LinuxJournalのリンカーとローダーは、この概念を明確に説明しています。また、古典的な名前a.outの由来についても説明します。(アセンブラ出力)
簡単な要約
c program --> [compiler] --> objectFile --> [linker] --> executable file (say, a.out)
実行可能ファイルを取得しました。このファイルを友人またはこのソフトウェアを必要としている顧客に提供してください:)
彼らがこのソフトウェアを実行するとき、それをコマンドラインに入力することによって言う./a.out
execute in command line ./a.out --> [Loader] --> [execve] --> program is loaded in memory
プログラムがメモリに読み込まれると、PC(プログラムカウンタ)が最初の命令を指すようにすることで、制御がこのプログラムに移ります。 a.out
リンカーとインタープリターは相互に排他的なインタープリターであり、コードを1行ずつ取得し、1行ずつ実行します。
コンパイラーは、特定のプログラミング言語で記述されたステートメントを処理し、コンピューターのプロセッサーが使用する機械語または「コード」に変換する特別なプログラムです
コンパイラは、コード行をプログラミング言語から機械語に変換します。
リンカーは、2つのプログラム間のリンクを作成します。
ローダーは、プログラムをメインデータベース、プログラムなどのメモリにロードします。