strace
出力では、実行可能ファイルが呼び出すライブラリへのパスはopen()
への呼び出しにあります。これは、動的にリンクされる実行可能ファイルによって使用されるシステムコールですか? dlopen()
はどうですか? open()
は、プログラムの実行に役割を果たすと私が推測した呼び出しではありません。
dlopen
はシステムコールではなく、 libdl library のライブラリ関数です。 strace
にはシステムコールのみが表示されます。
Linuxおよびその他の多くのプラットフォーム(特に、実行可能ファイルにELF形式を使用するプラットフォーム)では、dlopen
は、open()
でターゲットライブラリを開き、mmap()
。 mmap()
は、ここでは本当に重要な部分です。これは、ライブラリをプロセスのアドレス空間に組み込んで、CPUがそのコードを実行できるようにするものです。ただし、ファイルをopen()
する前に、ファイルをmmap()
する必要があります。
dlopenは、あなたが考えるように、共有ライブラリとは何の関係もありません。共有オブジェクトをロードするには、2つの方法があります。
main
関数が呼び出される直前に呼び出され、アプリケーションが次の関数を見つけるようにアプリケーションのプロセス空間を設定します図書館。これには、ライブラリをopen()
ingし、次にmmap()
ingしてから、いくつかのルックアップテーブルを設定します。libdl
とリンクすることをコンパイル時リンカーに通知し、そこから(最初のメソッドを使用して)dlopen()
およびdlsym()
関数を呼び出すことができます。 dlopenを使用すると、ライブラリへのハンドルを取得できます。このハンドルをdlsymで使用して、特定の関数への関数ポインターを受け取ることができます。この方法は、最初の方法よりもプログラマーにとってはるかに複雑であり(リンカーに自動的に設定させるのではなく、手動で設定する必要があるため)、また、より脆弱です(コンパイルできないため) -timeは、最初のメソッドで取得するように、正しい引数の型で関数を呼び出していることを確認します)が、利点は、実行時にロードする共有オブジェクトを決定できる(またはそれをロードするかどうかを決定できる)ことです。これは、プラグインタイプの機能用のインターフェイスです。最後に、dlopenインターフェースは、そのメカニズムが動的リンカーの正確な実装に依存するため、他の方法よりも移植性が低くなります(したがって、これらの違いを抽象化しようとするlibtoolのlibltdl
)。今日、ほとんどのオペレーティングシステムは、1987年後半にSunOS-4.0によって導入された共有ライブラリの方法を使用しています。このメソッドは、mmap()によるメモリのマッピングに基づいています。
1990年代の初めに、Sunは古いa.outベースのコード(当時のSolarisはすでにELFベース)をFreeBSDの人々に寄付し、このコードは後で他の多くのシステム(Linuxを含む)に引き渡されたという事実を踏まえて、プラットフォーム間で大きな違いがない理由を理解できます。
ltrace -S
最小限の例の分析は、mmap
がglibc 2.23で使用されていることを示しています
Glibc 2.23、Ubuntu 16.04では、dlopen
を使用する最小限のプログラムでlatrace -S
を実行します。
ltrace -S ./dlopen.out
ショー:
dlopen("libcirosantilli_ab.so", 1 <unfinished ...>
SYS_open("./x86_64/libcirosantilli_ab.so", 524288, 06267650550) = -2
SYS_open("./libcirosantilli_ab.so", 524288, 06267650550) = 3
SYS_read(3, "\177ELF\002\001\001", 832) = 832
SYS_brk(0) = 0x244c000
SYS_brk(0x246d000) = 0x246d000
SYS_fstat(3, 0x7fff42f9ce30) = 0
SYS_getcwd("/home/ciro/bak/git/cpp-cheat"..., 128) = 54
SYS_mmap(0, 0x201028, 5, 2050) = 0x7f1c323fe000
SYS_mprotect(0x7f1c323ff000, 2093056, 0) = 0
SYS_mmap(0x7f1c325fe000, 8192, 3, 2066) = 0x7f1c325fe000
SYS_close(3) = 0
SYS_mprotect(0x7f1c325fe000, 4096, 1) = 0
したがって、dlopen
がopen
+ mmap
を呼び出すことがすぐにわかります。
素晴らしいltrace
ツールは、ライブラリコールとシステムコールの両方をトレースするため、この場合に何が起こっているかを調べるのに最適です。
より詳細な分析は、open
がファイル記述子3
を返すことを示しています(stdin、out、およびerrの後に次に解放されます)。
read
はそのファイル記述子を使用しますが、- TODO理由mmap
の引数が4つに制限されており、5番目の引数なので、どのfdがそこで使用されたかがわかりません =。 strace
は、予想どおり3
が1であることを確認し、ユニバースの順序が復元されます。
勇敢な魂もglibcコードに挑戦できますが、迅速なgrepの後でmmap
を見つけることができず、怠惰です。
これでテスト GitHubでのボイラープレートのビルドの最小例 。
strace
は、システムコール(つまり、カーネルによって直接実装された関数)について報告します。動的ライブラリはカーネル関数ではありません。 dlopen
はCライブラリの一部であり、カーネルではありません。 dlopen
の実装は、open
(システムコール)を呼び出してライブラリファイルを開き、読み取り可能にします。