web-dev-qa-db-ja.com

リンク、オブジェクトファイル、実行可能ファイルの役割

  1. 他のライブラリを必要としないCまたはアセンブリプログラムの場合、リンクは必要ですか?つまり、Cからアセンブリへの変換、および/またはアセンブリからオブジェクトファイルへの変換は、リンクをたどらなくても十分でしょうか?

    それでもリンクが必要な場合、リンクするライブラリを必要としないオブジェクトファイルが1つしかない場合、どうしますか?

  2. 関連して、Linuxでは両方ともファイル形式がELFであるとすると、オブジェクトファイルと実行可能ファイルはどのように異なりますか?

    オブジェクトファイルは、実行できないELFファイルですか?

    オブジェクトファイルにリンクできる実行可能ファイルはありますか?はいの場合、それは実行可能ファイルを共有ライブラリに動的にリンクすることを意味しますか?

4
Tim

まず第一に、重要なプログラムが「他のライブラリを必要としない」ことは本当に難しいです。 glibcとmain()を呼び出すスタートアップコードもライブラリであることを忘れないでください。

ただし、はい。この場合でも、コンパイラ/アセンブラが通常ELF形式(または実行可能形式)を処理しないため、リンカーが必要です。正確には、通常いくつかのライブラリとリンクする必要があるため、なぜELFにコンパイルするのが面倒なのでしょうか。リンク可能なコード形式に焦点を合わせ、実行可能形式はリンカーに任せることをお勧めします。

PS:私はそれを忘れました.soもELFの変形です。しかし、それでも、サブフォーマットが異なり、実行可能ファイルの詳細がほとんどのコンパイラ/アセンブリに含まれていないという事実は変わりません。

はい、単一のツールを直接実行可能ファイルにコンパイルすることは十分に可能ですが、これは、単一のコマンドにコンパイラーとリンカーの両方が含まれていることを意味します。他のコードを追加しないのに、なぜ(非常に)特殊なケースを検討するのでしょうか?リンカーで行う方がはるかに論理的です。結局のところ、%99.9の場合に必要になります。

8
Javier

オペレーティングシステムによって異なります。ただし、一般的には、オブジェクトファイルを実行可能ファイルに変換するために何かが必要です。オブジェクトファイルは通常、リンカーへの入力として設計されており、直接実行されることはありません。

ライブラリをリンクする必要のない便利なプログラムは、あるとしてもごくわずかです。 (おそらく静的かもしれませんし、おそらく動的かもしれませんが、ライブラリインフラストラクチャがなければ、多くの有用な作業を行うことはできません。

1
Alger

プログラムを実行するには、(少なくとも)ローダーにリンクする必要があります。次の些細なコードを考えてみましょう。

tpost@tpost-desktop:~$ cat count.c
int main(void)
{
        unsigned int i;

        for (i = 0; i < 10; i++) {;;}

        return 0;
}

今、私たちはそれをコンパイルします:

tpost@tpost-desktop:~$ gcc -Wall -o count count.c

そして今、私たちはリンカが何をしたかを調べます:

    linux-gate.so.1 =>  (0x002b5000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00482000)
    /lib/ld-linux.so.2 (0x00241000)

    Version information:
    ./count:
            libc.so.6 (GLIBC_2.0) => /lib/tls/i686/cmov/libc.so.6
    /lib/tls/i686/cmov/libc.so.6:
            ld-linux.so.2 (GLIBC_PRIVATE) => /lib/ld-linux.so.2
            ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2
            ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2

興味深いのは、lddlinux-gate.so.1およびld-linux.so.2の物理ファイルを見つけられなかったことです。これは、両方がvirtualにある動的共有オブジェクトであるためですすべてのプロセスアドレス空間。共有オブジェクト自体はカーネルによって公開され、実際にプログラムをロードするために必要なコードが含まれています。これは、システムCライブラリと連携して機能します。

これを静的にリンクしましょう。

tpost@tpost-desktop:~$ gcc -static -Wall -o count count.c
tpost@tpost-desktop:~$ ldd -v count
        not a dynamic executable

ここではリンクの依存関係を排除していません。ローダーコードとシステムCライブラリを取得して、それらを実行可能ファイルの一部にするだけです。私の実行可能ファイルは、すでにメモリ内にあるそのコードの完全に適切なコピーを使用しなくなったため、これはややばかげているように見えます。

独自のローダーコードを記述して、システムCライブラリが提供するものを使用しないこともできますが、カーネルローダー自体への依存関係を失うことはありません。

これは非常にLinux指向の例ですが、要点を説明するために私が利用できるのはそれだけです:)

1
Tim Post