web-dev-qa-db-ja.com

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

CC++ または C# 。彼らは何であり、正確に何について話しているのか、そして彼らは何をリンクしているのか?

210
UnkwnTech

ソースコード(記述内容)から実行可能コード(実行内容)への移行には、2つの段階(ほとんどの場合、解釈済みコードの割引)があります。

1つは、ソースコードをオブジェクトモジュールに変換するコンパイルです。

2番目のリンクは、オブジェクトモジュールを結合して実行可能ファイルを形成するものです。

とりわけ、ソースコード(データベースアクセス、ネットワーク通信、グラフィカルユーザーインターフェイス用のライブラリなど)を表示せずにサードパーティライブラリを実行可能ファイルに含めること、または異なる言語でコードをコンパイルすること( Cおよびアセンブリコードなど)を使用して、それらをすべてリンクします。

静的ファイルを実行可能ファイルにリンクすると、リンク時にそのファイルの内容が含まれます。つまり、ファイルの内容は、実行する実行可能ファイルに物理的に挿入されます。

動的ににリンクすると、リンクされているファイルへのポインター(ファイルのファイル名など)が実行可能ファイルに含まれ、そのファイルの内容はリンク時に含まれません。後でrun実行可能ファイルを購入したときにのみ、これらの動的にリンクされたファイルが購入され、ディスク上のものではなく、実行可能ファイルのメモリ内コピーにのみ購入されます。

これは基本的に遅延リンクの方法です。偶数のmore遅延メソッド(一部のシステムでは遅延バインディングと呼ばれます)があり、実際にその中の関数を呼び出そうとするまで、動的にリンクされたファイルを持ち込みません。

静的にリンクされたファイルは、リンク時に実行可能ファイルに「ロック」されるため、変更されることはありません。実行可能ファイルによって参照される動的にリンクされたファイルは、ディスク上のファイルを置き換えるだけで変更できます。

これにより、コードを再リンクすることなく機能を更新できます。ローダーは、実行するたびに再リンクします。

これは良い面と悪い面の両方です-一方で、より簡単な更新とバグ修正を可能にし、他方では、更新に互換性がない場合、プログラムが動作しなくなる可能性があります-これは、一部の人々が動的にリンクされたライブラリを互換性のないライブラリに置き換えると、アプリケーションが破損する可能性があることに言及してください(これを行う開発者は、追い詰められ、ひどく処罰されることを期待すべきです)。


として、ユーザーが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ランタイムインポートライブラリ(動的ライブラリにあるものを宣言するものの、実際にはdefine itではないもの)にリンクされます。これにより、実際のコードが欠落していても、リンカーはリンクできます。

次に、実行時に、オペレーティングシステムローダーがメインプログラムとCランタイムDLL(ダイナミックリンクライブラリまたは共有ライブラリまたはその他の命名法)との遅いリンクを実行します。

Cランタイムの所有者は、いつでも新しいDLLをドロップして、更新またはバグ修正を提供できます。前述したように、これには長所と短所の両方があります。

411
paxdiablo

この質問に対する良い答えは、リンクが何であるかを説明するべきだと思います

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

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

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

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

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

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

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

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

214
Artelius

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

29
John D. Cook

上記の投稿のどれも実際に方法を示すが静的に何かをリンクし、あなたがそれを正しく行ったことを確認するため、この問題に対処します:

簡単な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ライブラリを手動でリンクしたりするのに時間がかかります。

幸運なことに、muslのような多くの組み込みCライブラリは、ライブラリのほとんどすべてすべてではない場合に対して静的リンクオプションを提供します。

ここでstrace作成したバイナリを見ると、プログラムが開始する前にライブラリにアクセスしていないことがわかります。

strace ./simpleprog

動的にリンクされたプログラムのstraceの出力と比較すると、静的にリンクされたバージョンのstraceがはるかに短いことがわかります。

13
user4832408

(私はC#を知りませんが、VM言語の静的リンクの概念を持つことは興味深いです)

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

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

2
artificialidiot