一部の共有ライブラリが実行可能ファイルであるかのように実行される理由と方法は何ですか?

一部の共有ライブラリが実行可能ファイルであるかのように実行される理由と方法は何ですか?

32ビットLinuxシステムでは、以下を呼び出します。

$ /lib/libc.so.6

64ビットシステムの場合

$ /lib/x86_64-linux-gnu/libc.so.6

シェルから次の出力を提供します。

GNU C Library stable release version 2.10.1, by Roland McGrath et al.
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.0 20090506 (Red Hat 4.4.0-4).
Compiled on a Linux >>2.6.18-128.4.1.el5<< system on 2009-08-19.
Available extensions:
    The C stubs add-on version 2.1.2.
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
    RT using linux kernel aio
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

これが起こる理由と方法は何ですか?他の共有ライブラリでも同じことをするにはどうすればよいですか?

/usr/lib実行ファイルを探すと、/usr/lib/libvlc.so.5.5.0実行結果が出ました。セグメンテーションエラー。 :-/

答え1

ライブラリにはmain()関数またはそれに対応するエントリポイントがあり、実行可能ファイルと共有オブジェクトの両方で使用できるようにコンパイルされます。

これはおすすめ私には動作しませんが、これを行う方法について。

これは別のものですSOに関する同様の質問に対する回答、恥ずかしい盗作、修正、説明を追加します。

まず、サンプルライブラリのソースは次のとおりです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を見てください。

答え2

GitHubのランダムglibcリポジトリで答えを見つけましょう。このバージョンはファイルに「バナー」を提供します。version.c

同じファイルにはいくつかの興味深い点があります。__libc_print_versionテキストを標準出力に印刷する機能とエントリ__libc_main (void)ポイントで文書化されたシンボル。したがって、ライブラリを実行するとこのシンボルが呼び出されます。

それでは、リンカやコンパイラは、これがエントリポイント関数であることをどのように正確に知ることができますか?

もっと深く掘り下げてみようファイルの生成。リンカーフラグの中には興味深いフラグがあります。

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

これは、ライブラリエントリポイントを設定するために使用されるリンカフラグです。ライブラリをビルドするときは、-e function_nameリンカにフラグを指定して実行可能な動作を有効にできます。正確にどんな役割を果たしますか?私たちに見せてください手動(やや古いですが、まだ有効です):

リンカーコマンド言語には、出力ファイルの最初の実行可能コマンド(対応するエントリポイント)を定義するように特別に設計されたコマンドが含まれています。引数は象徴的な名前です。

入力(記号)

シンボルの割り当てと同様に、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;

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

スタート=その他の記号;

(現在の文書を見つけることができますここ)

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

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

関連情報