「静的にリンクされた」および「動的にリンクされた」という用語をよく耳にしますが、これはC、C++、またはC#で記述されたコードを指すことがよくあります。それらは何なのか、正確には何について話しているのか、何をリンクしているのか?
5 に答える
ソース コード (作成したもの) から実行可能コード (実行したもの) に到達するには、2 つの段階があります (ほとんどの場合、解釈されたコードは無視します)。
1 つ目は、ソース コードをオブジェクト モジュールに変換するコンパイルです。
2 番目のリンクは、オブジェクト モジュールを組み合わせて実行可能ファイルを形成するものです。
この区別は、とりわけ、ソース コード (データベース アクセス、ネットワーク通信、およびグラフィカル ユーザー インターフェイス用のライブラリなど) を表示せずにサード パーティのライブラリを実行可能ファイルに含めることができるようにしたり、さまざまな言語でコードをコンパイルしたりするために行われます ( C とアセンブリ コードなど) を作成し、それらをすべてリンクします。
ファイルを実行可能ファイルに静的にリンクすると、そのファイルの内容がリンク時に含まれます。つまり、ファイルの内容は、実行する実行可能ファイルに物理的に挿入されます。
動的にリンクすると、リンクされているファイルへのポインター (ファイルのファイル名など) が実行可能ファイルに含まれ、そのファイルの内容はリンク時に含まれません。これらの動的にリンクされたファイルが購入されるのは、後で実行可能ファイルを実行したときだけであり、ディスク上のファイルではなく、実行可能ファイルのメモリ内コピーにのみ購入されます。
これは基本的に遅延リンクの方法です。実際にその中の関数を呼び出そうとするまで、動的にリンクされたファイルを取り込まない、さらに延期された方法 (一部のシステムでは遅延バインディングと呼ばれます) があります。
静的にリンクされたファイルは、リンク時に実行可能ファイルに「ロック」されるため、変更されることはありません。実行可能ファイルによって参照される動的にリンクされたファイルは、ディスク上のファイルを置き換えるだけで変更できます。
これにより、コードを再リンクすることなく機能を更新できます。ローダーは、実行するたびに再リンクします。
これは良い面と悪い面の両方があります - アップデートとバグ修正が容易になる一方で、アップデートに互換性がない場合、プログラムが動作しなくなる可能性があります - これは、一部の人々が恐れる恐ろしい「DLL 地獄」の原因となることがあります。動的にリンクされたライブラリを互換性のないものに置き換えると、アプリケーションが壊れる可能性があることに注意してください (ちなみに、これを行った開発者は、追い詰められて厳しく罰せられることを期待する必要があります)。
例として、ユーザー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 をドロップインして、更新またはバグ修正を提供できます。前述したように、これには長所と短所があります。
この質問に対する良い答えは、リンクとは何かを説明することだと思います。
たとえば、C コードをコンパイルすると、機械語に変換されます。実行されると、プロセッサが加算、減算、比較、「goto」、メモリの読み取り、メモリの書き込みなどを行う一連のバイト。このようなものは、オブジェクト (.o) ファイルに保存されます。
さて、ずっと前に、コンピューター科学者がこの「サブルーチン」を発明しました。このコードのチャンクを実行して、ここに戻ります。最も有用なサブルーチンを特別な場所に保存し、それを必要とするプログラムで使用できることに彼らが気付くのにそれほど時間はかかりませんでした。
初期の頃は、プログラマーはこれらのサブルーチンが配置されているメモリ アドレスを入力する必要がありました。のようなものCALL 0x5A62
。これらのメモリアドレスを変更する必要がある場合、これは面倒で問題がありました。
したがって、プロセスは自動化されました。を呼び出すプログラムを作成しましたがprintf()
、コンパイラは のメモリ アドレスを知りませんprintf
。したがって、コンパイラは単に書き込み、オブジェクト ファイルに「この 0x0000 をprintfCALL 0x0000
のメモリ ロケーションに置き換える必要がある」というメモを追加します。
静的リンクとは、リンカー プログラム (GNU のものはldprintf
と呼ばれます) がのマシン コードを実行可能ファイルに直接追加し、0x0000 を のアドレスに変更することを意味しますprintf
。これは、実行可能ファイルが作成されたときに発生します。
動的リンケージは、上記のステップが発生しないことを意味します。実行可能ファイルには、「0x000 を printf のメモリ位置に置き換える必要があります」というメモがまだあります。オペレーティング システムのローダーは、プログラムが実行されるたびに、printf コードを見つけてメモリにロードし、CALL アドレスを修正する必要があります。
プログラムが静的にリンクされるいくつかの関数 (通常は静的にリンクされる標準ライブラリ関数などprintf
) と、動的にリンクされる他の関数を呼び出すことはよくあります。静的なものは実行可能ファイルの「一部になり」、動的なものは実行可能ファイルの実行時に「参加」します。
どちらの方法にも長所と短所があり、オペレーティング システムによって違いがあります。でも聞かなかったのでここで終わりにします。
静的にリンクされたライブラリは、コンパイル時にリンクされます。動的にリンクされたライブラリは、実行時に読み込まれます。静的リンクは、ライブラリ ビットを実行可能ファイルに焼き付けます。動的リンクは、ライブラリへの参照のみを焼き付けます。動的ライブラリのビットは別の場所に存在し、後で交換できます。
上記の投稿のいずれも、何かを静的にリンクする方法を実際に示しておらず、それが正しく行われたことを確認するため、この問題に対処します。
簡単な 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 つです。