「静的にリンクされた」および「動的にリンクされた」とはどういう意味ですか?


229

「静的にリンクされた」および「動的にリンクされた」という用語をよく耳にしますが、CC ++、またはC#で記述されたコードを指すことがよくあります。彼らは何であり、彼らは何を話しているのですか、そして彼らは何を結び付けていますか?

回答:


445

ソースコード(作成した内容)から実行可能コード(実行した内容)への移行には、(ほとんどの場合、解釈されたコードを割り引く)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をドロップして、更新またはバグ修正を提供できます。前述のとおり、これには利点と欠点の両方があります。


11
私が間違っている場合は修正してください。ただし、Windowsでは、ソフトウェアが動的にリンクされている場合でも、インストールに独自のライブラリが含まれる傾向があります。パッケージマネージャを備えた多くのLinuxシステムでは、多くの動的にリンクされたライブラリ(「共有オブジェクト」)が実際にソフトウェア間で共有されます。
ポールフィッシャー

6
@PaulF:Windowsコモンコントロール、DirectX、.NETなどのアプリケーションには多くのものが付属していますが、Linuxでは依存関係を管理するためにaptやyumなどを使用する傾向があるため、その意味で正しい。DLLがそれらを共有しない傾向があるため、独自のコードを出荷するWinアプリ。
paxdiablo 2008年

31
DLLを更新して下位互換性を損なう人々のために、9番目の地獄の輪で予約されている特別な場所があります。はい、インターフェースが消えたり変更されたりすると、動的リンクはヒープに分類されます。それが行われるべきではない理由です。必ずfunction2()をDLLに追加しますが、人々が使用している場合はfunction()を変更しないでください。これを処理する最善の方法は、function()をfunction2()を呼び出すような方法で再コーディングすることですが、function()のシグネチャは変更しないでください。
paxdiablo

1
@ポール・フィッシャー、これは遅いことは知っていますが... Windows DLLに同梱されているライブラリは完全なライブラリではなく、DLLに何が含まれているかをリンカーに伝える単なるスタブの集まりです。その後、リンカはDLLをロードするために情報を.exeに自動的に配置でき、シンボルは未定義として表示されません。
Mark Ransom 2011年

1
@Santropedro、あなたは、lib、import、DLLの名前の意味に関してすべての点で正しいです。サフィックスはだけなので(例えば、DLLが有してもよいことにあまり読んでいない大会である.dll.so説明するような答えを考える-拡張子)概念をではなく、正確な説明であること。そして、テキストによると、これはCランタイムファイルのみの静的リンクと動的リンクを示す例なので、そうです、それがすべてのファイルで `crtが示していることです。
paxdiablo

221

この質問への良い答え、リンクとは何かを説明するべきだと思います。

たとえばCコードをコンパイルすると、機械語に変換されます。実行時にプロセッサに追加、減算、比較、「goto」、メモリの読み取り、メモリの書き込みなどを実行させる一連のバイト。このものはオブジェクト(.o)ファイルに保存されます。

さて、昔、コンピュータ科学者たちはこの「サブルーチン」を発明しました。このコードのチャンクを実行して、ここに戻ります。最も有用なサブルーチンを特別な場所に格納し、それらを必要とするプログラムで使用できることに気づくまで、それほど時間はかかりませんでした。

現在、初期の段階では、プログラマはこれらのサブルーチンが配置されていたメモリアドレスをパンチインする必要があります。のようなものCALL 0x5A62。これらのメモリアドレスを変更する必要がある場合、これは面倒で問題がありました。

したがって、プロセスは自動化されました。を呼び出すプログラムを作成しましたがprintf()、コンパイラはのメモリアドレスを認識していませんprintf。したがって、コンパイラはを書き込みCALL 0x0000、オブジェクトファイルに「この0x0000をprintfのメモリロケーションで置き換える必要があります」というメモを追加します。

静的リンケージとは、リンカープログラム(GNUプログラムはldと呼ばprintfれます)がのマシンコードを実行可能ファイルに直接追加し、0x0000をのアドレスに変更することを意味しますprintf。これは、実行可能ファイルが作成されたときに発生します。

動的リンケージは、上記のステップが発生しないことを意味します。実行可能ファイルには、「0x000をprintfのメモリ位置で置き換える必要があります」というメモがまだ残っています。オペレーティングシステムのローダーは、プログラムが実行されるたびに、printfコードを見つけてメモリにロードし、CALLアドレスを修正する必要があります

静的にリンクされる関数(printf通常、標準ライブラリ関数は通常静的にリンクされます)と動的にリンクされる他の関数を呼び出すのは、プログラムにとって一般的です。静的なものは実行可能ファイルの「一部」となり、動的なものは実行可能ファイルの実行時に「参加」します。

どちらの方法にも長所と短所があり、オペレーティングシステムには違いがあります。しかし、あなたが尋ねなかったので、これをここで終わります。


4
私もやりましたが、選択できるのは1つだけです。
UnkwnTech 2008年

1
Artelius、私はこれらのクレイジーな低レベルのものがどのように機能するかについてのあなたの説明についていくつか深く調べています。上記の事柄について深い知識を得るために私たちが読む必要がある本を返信してください。ありがとうございました。
mahesh 2008

1
申し訳ありませんが、おすすめの本はありません。最初にアセンブリ言語を学ぶべきです。それからウィキペディアはそのようなトピックのまともな概要を与えることができます。あなたはGNUのldドキュメントを見たいかもしれません。
Artelius 2009

31

静的にリンクされたライブラリは、コンパイル時にリンクされます。動的にリンクされたライブラリは実行時にロードされます。静的リンクは、ライブラリビットを実行可能ファイルに焼き付けます。ダイナミックリンクは、ライブラリへの参照でのみベイクします。動的ライブラリのビットは別の場所にあり、後で交換することができます。


16

上記の投稿どれも実際に何かを静的にリンクする方法示しておらず、正しくリンクしたことがわかるので、この問題に対処します。

単純な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がはるかに短いことがわかります。


2

(C#はわかりませんが、VM言語の静的リンクの概念があると興味深いです)

動的リンクには、プログラムからの参照しかない必要な機能を見つける方法を知ることが含まれます。言語ランタイムまたはOSは、ファイルシステム、ネットワーク、またはコンパイル済みコードキャッシュでコードを検索し、参照を照合して、再配置など、メモリ内のプログラムイメージに統合するためにいくつかの措置を講じます。これらはすべて実行時に行われます。これは、手動またはコンパイラーによって実行できます。めちゃくちゃになってしまうリスク(つまりDLLの地獄)で更新する機能があります。

静的リンクはコンパイル時に行われ、すべての機能部分がどこにあるかをコンパイラーに伝え、それらを統合するように指示します。検索、あいまいさ、再コンパイルなしに更新する機能はありません。すべての依存関係は、プログラムイメージと物理的に1つです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.