回答:
ソースコード(作成した内容)から実行可能コード(実行した内容)への移行には、(ほとんどの場合、解釈されたコードを割り引く)2つの段階があります。
1つ目は、ソースコードをオブジェクトモジュールに変換するコンパイルです。
2番目のリンクは、オブジェクトモジュールを結合して実行可能ファイルを形成するものです。
特に、ソースコード(データベースアクセス、ネットワーク通信、グラフィカルユーザーインターフェイスのライブラリなど)を表示せずにサードパーティのライブラリを実行可能ファイルに含めたり、さまざまな言語でコードをコンパイルしたりすることで区別されます( Cとアセンブリコードなど)、それらをすべて一緒にリンクします。
あなたはときに静的実行可能ファイルにファイルをリンクし、そのファイルの内容は、リンク時に含まれています。つまり、ファイルの内容は、実行する実行可能ファイルに物理的に挿入されます。
動的にリンクすると、リンクされているファイルへのポインタ(ファイルのファイル名など)が実行可能ファイルに含まれ、リンク時にそのファイルの内容は含まれません。これらの動的にリンクされたファイルが購入され、後で実行可能ファイルを実行したときにのみ、ディスク上のファイルではなく、実行可能ファイルのメモリ内コピーにのみ購入されます。
これは基本的に据え置きリンクの方法です。でもありますより多くのあなたが実際にそれ内の関数を呼び出そうとするまで、動的にリンクされたファイルにもたらすことはありません(後半いくつかのシステムでは結合と呼ばれる)繰延方法が。
静的にリンクされたファイルは、リンク時に実行可能ファイルに「ロック」されるため、変更されることはありません。実行可能ファイルによって参照される動的にリンクされたファイルは、ディスク上のファイルを置き換えるだけで変更できます。
これにより、コードを再リンクすることなく機能を更新できます。ローダーは、実行するたびに再リンクします。
これは良い点と悪い点の両方です-一方では、更新とバグ修正が簡単になり、他方では、更新に互換性がない場合にプログラムが動作しなくなる可能性があります-これは、一部の人々が恐れている「DLL hell」の原因になる場合があります動的にリンクされたライブラリを互換性のないライブラリに置き換えると、アプリケーションが壊れる可能性があることを述べます(これを行う開発者は、追い詰められ、厳しく罰せられることを期待しているはずです)。
例として、main.c
静的リンクと動的リンクのためにユーザーがファイルをコンパイルするケースを見てみましょう。
Phase Static Dynamic
-------- ---------------------- ------------------------
+---------+ +---------+
| main.c | | main.c |
+---------+ +---------+
Compile........|.........................|...................
+---------+ +---------+ +---------+ +--------+
| main.o | | crtlib | | main.o | | crtimp |
+---------+ +---------+ +---------+ +--------+
Link...........|..........|..............|...........|.......
| | +-----------+
| | |
+---------+ | +---------+ +--------+
| main |-----+ | main | | crtdll |
+---------+ +---------+ +--------+
Load/Run.......|.........................|..........|........
+---------+ +---------+ |
| main in | | main in |-----+
| memory | | memory |
+---------+ +---------+
静的なケースでは、メインプログラムとCランタイムライブラリがリンク時に(開発者によって)リンクされていることがわかります。ユーザーは通常、実行可能ファイルを再リンクできないため、ライブラリの動作に行き詰まっています。
動的な場合、メインプログラムはCランタイムインポートライブラリ(動的ライブラリの内容を宣言するが実際には定義しないもの)とリンクされます。これにより、実際のコードが欠落している場合でも、リンカーはリンクできます。
次に、実行時に、オペレーティングシステムローダーはメインプログラムとCランタイムDLL(ダイナミックリンクライブラリまたは共有ライブラリまたはその他の命名法)のレイトリンクを実行します。
Cランタイムの所有者は、いつでも新しいDLLをドロップして、更新またはバグ修正を提供できます。前述のとおり、これには利点と欠点の両方があります。
.dll
か.so
説明するような答えを考える-拡張子)概念をではなく、正確な説明であること。そして、テキストによると、これはCランタイムファイルのみの静的リンクと動的リンクを示す例なので、そうです、それがすべてのファイルで `crtが示していることです。
この質問への良い答えは、リンクとは何かを説明するべきだと思います。
たとえばCコードをコンパイルすると、機械語に変換されます。実行時にプロセッサに追加、減算、比較、「goto」、メモリの読み取り、メモリの書き込みなどを実行させる一連のバイト。このものはオブジェクト(.o)ファイルに保存されます。
さて、昔、コンピュータ科学者たちはこの「サブルーチン」を発明しました。このコードのチャンクを実行して、ここに戻ります。最も有用なサブルーチンを特別な場所に格納し、それらを必要とするプログラムで使用できることに気づくまで、それほど時間はかかりませんでした。
現在、初期の段階では、プログラマはこれらのサブルーチンが配置されていたメモリアドレスをパンチインする必要があります。のようなものCALL 0x5A62
。これらのメモリアドレスを変更する必要がある場合、これは面倒で問題がありました。
したがって、プロセスは自動化されました。を呼び出すプログラムを作成しましたがprintf()
、コンパイラはのメモリアドレスを認識していませんprintf
。したがって、コンパイラはを書き込みCALL 0x0000
、オブジェクトファイルに「この0x0000をprintfのメモリロケーションで置き換える必要があります」というメモを追加します。
静的リンケージとは、リンカープログラム(GNUプログラムはldと呼ばprintf
れます)がのマシンコードを実行可能ファイルに直接追加し、0x0000をのアドレスに変更することを意味しますprintf
。これは、実行可能ファイルが作成されたときに発生します。
動的リンケージは、上記のステップが発生しないことを意味します。実行可能ファイルには、「0x000をprintfのメモリ位置で置き換える必要があります」というメモがまだ残っています。オペレーティングシステムのローダーは、プログラムが実行されるたびに、printfコードを見つけてメモリにロードし、CALLアドレスを修正する必要があります。
静的にリンクされる関数(printf
通常、標準ライブラリ関数は通常静的にリンクされます)と動的にリンクされる他の関数を呼び出すのは、プログラムにとって一般的です。静的なものは実行可能ファイルの「一部」となり、動的なものは実行可能ファイルの実行時に「参加」します。
どちらの方法にも長所と短所があり、オペレーティングシステムには違いがあります。しかし、あなたが尋ねなかったので、これをここで終わります。
ld
ドキュメントを見たいかもしれません。
上記の投稿はどれも実際に何かを静的にリンクする方法を示しておらず、正しくリンクしたことがわかるので、この問題に対処します。
単純なCプログラム
#include <stdio.h>
int main(void)
{
printf("This is a string\n");
return 0;
}
Cプログラムを動的にリンクする
gcc simpleprog.c -o simpleprog
そしてfile
、バイナリで実行します:
file simpleprog
そして、それはそれが次の線に沿って何かに動的にリンクされていることを示します:
「simpleprog:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(SYSV)、動的にリンク(共有ライブラリを使用)、GNU / Linux 2.6.26、BuildID [sha1] = 0xf715572611a8b04f686809d90d1c0d75c6028f0f、ストリップされない」
代わりに、今回はプログラムを静的にリンクします。
gcc simpleprog.c -static -o simpleprog
この静的にリンクされたバイナリでファイルを実行すると、次のように表示されます。
file simpleprog
「simpleprog:ELF 64ビットLSB実行可能ファイル、x86-64、バージョン1(GNU / Linux)、静的にリンク、GNU / Linux 2.6.26用、BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b、ストリップされない」
そして、それは幸せに静的にリンクされていることがわかります。悲しいことに、すべてのライブラリがこの方法で静的にリンクするのが簡単であるとは限らずlibtool
、オブジェクトコードとCライブラリを手動で使用またはリンクするための多大な労力が必要になる場合があります。
幸いにも、多くの組み込みCライブラリは、すべてではないにしてもmusl
ほとんどすべてのライブラリに静的リンクオプションを提供しています。
これでstrace
、作成したバイナリが表示され、プログラムが始まる前にアクセスしたライブラリがないことがわかります。
strace ./simpleprog
strace
動的にリンクされたプログラムの出力と比較すると、静的にリンクされたバージョンのstraceがはるかに短いことがわかります。
(C#はわかりませんが、VM言語の静的リンクの概念があると興味深いです)
動的リンクには、プログラムからの参照しかない必要な機能を見つける方法を知ることが含まれます。言語ランタイムまたはOSは、ファイルシステム、ネットワーク、またはコンパイル済みコードキャッシュでコードを検索し、参照を照合して、再配置など、メモリ内のプログラムイメージに統合するためにいくつかの措置を講じます。これらはすべて実行時に行われます。これは、手動またはコンパイラーによって実行できます。めちゃくちゃになってしまうリスク(つまりDLLの地獄)で更新する機能があります。
静的リンクはコンパイル時に行われ、すべての機能部分がどこにあるかをコンパイラーに伝え、それらを統合するように指示します。検索、あいまいさ、再コンパイルなしに更新する機能はありません。すべての依存関係は、プログラムイメージと物理的に1つです。