GNU/Linux >> Linux の 問題 >  >> Linux

一部の共有ライブラリは、なぜ、どのように実行可能であるかのように実行できるのですか?

そのライブラリには main() があります 関数または同等のエントリ ポイントであり、実行可能ファイルとしても共有オブジェクトとしても役立つようにコンパイルされています。

これを行う方法について 1 つの提案がありますが、私にはうまくいきません。

これは、S.O. に関する同様の質問に対する別の回答です。恥知らずに盗用し、微調整し、少し説明を追加します。

まず、サンプル ライブラリ test.c のソースです。 :

#include <stdio.h>                  

void sayHello (char *tag) {         
    printf("%s: Hello!\n", tag);    
}                                   

int main (int argc, char *argv[]) { 
    sayHello(argv[0]);              
    return 0;                       
}                   

それをコンパイルします:

gcc -fPIC -pie -o libtest.so test.c -Wl,-E

ここでは、共有ライブラリ (-fPIC) をコンパイルしています。 )、しかしそれが通常の実行可能ファイルであることをリンカーに伝えます (-pie )、そのシンボル テーブルをエクスポート可能にする (-Wl,-E )、それに対して便利にリンクできるようにします。

そして、 file でも 共有オブジェクトであると表示されますが、実行可能ファイルとして機能します:

> ./libtest.so 
./libtest.so: Hello!

次に、本当に動的にリンクできるかどうかを確認する必要があります。サンプルプログラム program.c :

#include <stdio.h>

extern void sayHello (char*);

int main (int argc, char *argv[]) {
    puts("Test program.");
    sayHello(argv[0]);
    return 0;
}

extern の使用 ヘッダーを作成する必要がなくなります。これをコンパイルします:

gcc program.c -L. -ltest

実行する前に、 libtest.so のパスを追加する必要があります ダイナミック ローダーの場合:

export LD_LIBRARY_PATH=./

現在:

> ./a.out
Test program.
./a.out: Hello!

そして ldd a.out libtest.so へのリンクが表示されます .

おそらく glibc 自体ほど移植性がないため、これが glibc の実際のコンパイル方法ではないことに注意してください (man gcc を参照)。 -fPIC に関して と -pie スイッチ)が、基本的なメカニズムを示しています。実際の詳細については、ソースの makefile を確認する必要があります。


GitHub のランダムな glibc リポジトリで答えを探しましょう。このバージョンでは、ファイル version.c に「バナー」が用意されています。 .

同じファイルには興味深い点がいくつかあります:__libc_print_version テキストを stdout と __libc_main (void) に出力する関数 シンボルはエントリ ポイントとして文書化されています。そのため、このシンボルはライブラリの実行時に呼び出されます。

では、リンカまたはコンパイラは、これがエントリ ポイント関数であることをどのように正確に認識しているのでしょうか?

makefile に飛び込みましょう。リンカー フラグには興味深いものがあります:

# Give libc.so an entry point and make it directly runnable itself.
LDFLAGS-c.so += -e __libc_main

したがって、これはライブラリのエントリ ポイントを設定するためのリンカ フラグです。ライブラリを構築するとき、 -e function_name を提供できます リンカーが実行可能な動作を有効にするためのフラグ。実際には何をしますか?マニュアルを見てみましょう (多少古いですが、まだ有効です):

<ブロック引用>

リンカーコマンド言語には、出力ファイル内の最初の実行可能命令 (そのエントリポイント) を定義するためのコマンドが含まれています。その引数はシンボル名です:

ENTRY(シンボル)

シンボルの割り当てと同様に、ENTRY コマンドは、コマンド ファイル内の独立したコマンドとして、または SECTIONS コマンド内のセクション定義の中に配置することができます-レイアウトにとって最も意味のあるものは何でも.

ENTRY は、エントリ ポイントを選択するいくつかの方法の 1 つにすぎません。次のいずれかの方法でそれを示すことができます (優先度の降順で表示:リストの上位にあるメソッドが下位にあるメソッドをオーバーライドします)。

the `-e' entry command-line option;
the ENTRY(symbol) command in a linker control script;
the value of the symbol start, if present;
the address of the first byte of the .text section, if present;
The address 0. 

たとえば、これらの規則を使用して、割り当てステートメントでエントリ ポイントを生成できます。入力ファイル内でシンボル開始が定義されていない場合は、単純に定義して、適切な値を割り当てることができます---

開始 =0x2020;

この例では絶対アドレスを示していますが、任意の式を使用できます。たとえば、入力オブジェクト ファイルがエントリ ポイントに他のシンボル名規則を使用している場合、開始アドレスを含む任意のシンボルの値を割り当てることができます:

start =other_symbol;

(現在のドキュメントはここにあります)

ld コマンドラインオプション -e を指定すると、リンカーは実際にエントリポイント関数を使用して実行可能ファイルを作成します (これが最も一般的なソリューションです)、関数シンボル start を提供します 、またはアセンブラのシンボル アドレスを指定します。

ただし、他のリンカーでの動作は保証されていないことに注意してください (llvm の lld に同じフラグがあるかどうかはわかりません)。 SO ファイルに関する情報を提供する以外の目的でこれが役立つ理由がわかりません。


Linux
  1. キャッシュとしてのRedis:その仕組みと使用理由

  2. システムにログオンしているユーザーとそのユーザーが行っていることを確認する方法

  3. データが重要である理由とその保護方法

  1. 空の環境で、実行可能ファイルはどのように見つかりますか?

  2. 共有ライブラリがインストールされているかどうかを確認するには?

  3. /lib と /lib64 があるのに /bin しかないのはなぜですか?

  1. なぜScpはとても遅いのですか、そしてそれをより速くする方法は?

  2. 共有ライブラリのロードとRAMの使用?

  3. 一部のポートがNmapによって報告され、他のポートはフィルタリングされないのはなぜですか?