Linuxでライブラリをロードするためにどのシステムコールが使用されますか?

Linuxでライブラリをロードするためにどのシステムコールが使用されますか?

strace出力で実行可能ファイルによって呼び出されたライブラリへのパスはにありますopen()。これは動的にリンクされた実行可能ファイルによって使用されるシステムコールですか?何についてdlopen()open()おそらく、これはプログラムの実行に重要な役割を果たす呼び出しではないようです。

答え1

dlopenシステムコールではなくライブラリ関数libdlライブラリ。にはシステムコールのみが表示されますstrace

Linuxや他の多くのプラットフォーム(特に実行可能ファイルにELF形式を使用するプラットフォーム)では、ターゲットdlopenライブラリを使用してopen()それをメモリにマッピングしてこれを実行しますmmap()mmap()ここに実際に重要な部分があります。ライブラリをプロセスのアドレス空間にマージして、CPUがそのコードを実行できるようにします。しかし、これをopen()行うには、まずファイルを入手する必要がありますmmap()

答え2

dlopenは共有ライブラリだと思うものとは何の関係もありません。共有オブジェクトをロードするには2つの方法があります。

  1. 特定の共有ライブラリの関数を使用したいとコンパイル時リンカ(ld、通常はコンパイラを介して呼び出される)に通知します。このアプローチでは、コンパイル時リンカを実行するときにライブラリの名前を知る必要がありますが、プログラムに静的にリンクされているかのようにライブラリの関数を呼び出すことができます。アプリケーションが実行されると、main関数を呼び出す前に動的ランタイムリンカー(ld.so)が呼び出され、アプリケーションがライブラリ内の関数を見つけることができるように、アプリケーションのプロセススペースを設定します。これには、open()lubrary、mmap()ing、および一部のルックアップテーブル設定が含まれます。
  2. コンパイル時にリンカーに接続したいと思ったらlibdl(最初の方法を使用して)、そのリンカーからdlopen()関数dlsym()を呼び出すことができます。 dlopenを使用すると、dlsymと一緒に使用して、特定の関数への関数ポインタを受け取ることができるライブラリへのハンドルを取得できます。このアプローチは、プログラマにとって最初のアプローチよりはるかに複雑であり(リンカが自動的に設定するのではなく手動で設定する必要があるため)、さらに脆弱です(コンパイルされた結果が得られないため)。 - 最初の方法で取得した正しい引数型を使用して関数を呼び出していることを確認する時間。ただし、利点は、ロードする共有オブジェクト(またはまったくロードするかどうか)を実行時に決定できることです。これはプラグインタイプ機能のためのインターフェースです。最後に、dlopenインタフェースは、そのメカニズムが動的リンカ(したがってlibltdlこれらの違いを抽象化しようとするlibtool)の正確な実装に依存しているため、他の方法よりも移植性が低くなります。

答え3

ltrace -S最小限の例を分析すると、mmapglibc 2.23で使用されていることがわかります。

glibc 2.23、Ubuntu 16.04では、以下をlatrace -S使用して最小プログラムで実行されますdlopen

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れたことをすぐに見ることができます。openmmap

この素晴らしいltraceツールはライブラリ呼び出しとシステム呼び出しを追跡できるため、このシナリオで何が起こっているのかを判断するのに適しています。

慎重な分析によると、openファイル記述子3(stdin、out、およびerrの後に使用可能な記述子)を返すことがわかりました。

readその後、対応するファイル記述子を使用しますが、TODOの引数はmmap4つに制限されており、5番目の引数であるため、どのfdがそこで使用されているかわかりません。strace予想通りこれが確認され、3宇宙の秩序が回復した。

勇敢な人なら glibc コードをナビゲートすることもできますが、高速な grep の後にも見つからず怠惰ですmmap

これでテストGitHubのビルド定型句を使用した最小例

答え4

straceシステムコール(カーネルで直接実装された関数など)を報告します。動的ライブラリはカーネル関数ではありません。dlopenカーネルではなく、Cライブラリの一部です。ライブラリファイルを読み込むために開くためにdlopen実装が呼び出されます(システムコール)。open

関連情報