C言語のLinux Dlopenシステム

C Yan Yunolinux Dlopenshisutemu



ライブラリ関数 dlopen() は、C 言語で非常に便利な関数です。この関数は、新しいライブラリを開いた後、ライブラリをメモリにロードします。通常、コンパイル時に不明なライブラリ シンボルをロードするために使用します。 dlopen() は、私たちのプログラムで使用される関数です。 DL ライブラリは、Dlfcn.h で定義されている dlopen() を実装します。 dlopen 関数には、ライブラリ ファイルの名前とフラグの 2 つのパラメータが必要です。ファイルの名前は動的ライブラリであり、ライブラリの依存関係をすぐに計算するかどうかを定義します。 dlopen() は、不透明な値と見なされるべき「ハンドル」を返し、他の DL ライブラリ操作はこれを使用します。ロードに失敗した場合、dlopen() は NULL を返します。ただし、dlopen() は、同じライブラリを何度もロードすると、同じファイル ハンドルを返します。

dlopen 関数を使用している間、コンパイラは使用している型とプロトタイプを認識していないため、潜在的なエラーを調べません。標準ロード用の dlopen 関数の展開は、いくつかの小さな状況を除いて、それによって促進されるようには見えません。ちなみに、これは内観を改善するためのアプローチです。共有モジュールが現在別のプログラムによって使用されている場合、メモリ レイアウトの最適化は条件付き読み込みには特に関心がありません。以前に使用したライブラリをロードしても、メモリ フットプリントは増加しません。コンパイラの監視を回避することは危険であり、適切なバグ作成に役立ちます。さらに、可能なコンパイラの最適化が欠けています。

例 1:

ここで、次の例を考えて、C 言語での dlopen 関数の機能を確認してください。最初のステップでは、いくつかの C 標準ライブラリをロードします。ここでは、dlopen モード引数の構築中にマクロを定義するために使用される新しいライブラリ「dlfcn.h」をロードします。







次に、プログラム内に別のライブラリ「gnu/lib-name.h」を導入します。 GNU libc に含まれる共有ライブラリ ファイルは、定義されているマクロに従ってユーザー プログラムによって検出されます。 GNU C ライブラリは、GNU および GNU/Linux オペレーティング システムのほか、さまざまなその他の Linux ベースのシステム用の基本的なライブラリを提供します。その後、main メソッドの実装があります。その中で、ポインタ オブジェクトの「ハンドル」を void キーワードで宣言します。データ型が double のポインター正弦関数を宣言します。エラー処理用のポインターオブジェクト「エラー」の別の宣言があります。



その後、「ハンドル」オブジェクト内で dlopen 関数を呼び出します。 dlopen は、LIBM_SO と「RTLD_LAZY」の 2 つの引数を取ります。ここで、「LIBM_SO」は、三角関数などの数学関数を提供するライブラリ ファイルの名前です。サイン関数を使用するため、この共有ライブラリが必要です。 「RTLD_LAZY」は、dlopen 関数を呼び出す別の引数です。特定のシンボルが初めて参照されるとき、再配置は実装によって決定された時間に実行される必要があります。



プロセスは実行可能オブジェクト ファイル内のすべてのシンボルを参照するわけではないため、RTLD LAZY を指定すると、動的なシンボル バインディングを有効にする実装のパフォーマンスが向上します。次に、ハンドル オブジェクトが dlopen 関数の実行に失敗した場合のエラー処理のための if-else 条件があります。 dlerror を呼び出してエラーをクリアします。





dlerror() 関数は、人間が読めるヌル終了文字列を提供し、最後の dlerror 呼び出し以降の dlopen API 呼び出しの 1 つへの呼び出しによって引き起こされた最近のエラーのレポートを指定します。次に、「(*void**)(&sine)= dlsym(handle, sin)」のように関数をキャストします。これは奇妙なことですが、キャストはコンパイラからの警告を回避する ISO C に準拠しています。 dlopen() 関数を介してアクセスできるダイナミック リンク モジュール内で指定されたシンボルのパスを取得する dlsym 関数を使用します。

また、dlerror() が NULL でない場合に生成される標準エラーに対して、再度 if-else 演算を実行します。次に、計算する正弦値を指定する printf ステートメントがあります。最後のステップでは、dlopen() によって返されたハンドルの dlclose を呼び出して、その共有オブジェクトを閉じます。



#include
#include
#include
#include

整数
主要 ( 整数 argc チャー ** argv )
{
空所 * 扱う ;
ダブル ( * 彼らのもの ) ( ダブル ) ;
チャー * エラー ;

扱う = ドロペン ( LIBM_SO RTLD_LAZY ) ;
もしも ( ! 扱う ) {
fprintf ( 標準エラー '%s \n ' dlエラー ( ) ) ;
出口 ( EXIT_FAILURE ) ;
}
dlエラー ( ) ;

* ( 空所 ** ) ( & 彼らの ) = dlsym ( 扱う 'それなし' ) ;

もしも ( ( エラー = dlエラー ( ) ) != ヌル ) {
fprintf ( 標準エラー '%s \n ' エラー ) ;
出口 ( EXIT_FAILURE ) ;
}

printf ( '%f \n ' ( * 彼らの ) ( 4.0 ) ) ;
閉じる ( 扱う ) ;
出口 ( EXIT_SUCCESS ) ;
}

-ldl オプションを C コンパイル コマンドで使用します。これは、dlopen リンク インターフェイスのライブラリであり、必須であるためです。 dlopen ファイルを実行すると、前に与えられた値の正弦値が表示されます。

例 2:

ここで、dlopen 関数を使用する別の例を取り上げます。 dlopen コードの実装に必要なすべての C ライブラリをプログラムにロードします。次に、main メソッド内でプログラムを開始します。ここでは、変数「src」の宣言で文字列を定義します。次に、ポインター変数「strlen」、「handle」、および「error」を宣言します。

次に、ハンドル変数を呼び出し、dlopen 関数をデプロイします。 dlopen 関数は、文字列処理関数用の共有ライブラリ「libstr.so」と、前の例で既に説明したフラグ「RTLD_LAZY」を入力します。 「error」変数内で dlerror 関数を呼び出して、dlopen 関数によって生成されたエラーをクリアします。 if-else を使用してエラーを調べます。

次に、dlsym 関数を使用して strlen 関数のアドレスを取得し、これを実行しながらエラーを検証します。この後、printf 関数を使用して strnlen 関数を呼び出し、指定された文字列の長さを返します。最後に、dlclose 関数で共有ライブラリを閉じます。

#include
#include
#include
#include
整数 主要 ( 空所 )
{
チャー * ソース = 「こんにちはリナックス」 ;
整数 ( * ストレン ) ( 定数 チャー * ) ;
空所 * 扱う ;
チャー * エラー ;


扱う = ドロペン ( 「./libstr.so」 RTLD_LAZY ) ;
エラー = dlエラー ( ) ;
もしも ( ! 扱う || エラー != ヌル ) { printf ( 「ライブラリのロードに失敗しました! \n %s \n ' エラー ) ;
戻る - 1 ; }

ストレン = dlsym ( 扱う 「ストレン」 ) ;
エラー = dlエラー ( ) ;
もしも ( ! ストレン || エラー == ヌル ) { printf ( '%s \n ' エラー ) ; 戻る - 1 ; }

printf ( '文字列の長さ:%d \n ' ストレン ( ソース ) ) ;
閉じる ( 扱う ) ;
戻る 0 ;
}

指定されたプログラムの実行には、次のコマンドを使用します。ここでは、-lstr フラグが文字列長関数に使用され、ldl が dlopen ライブラリ ファイルに使用されます。コンパイルされたプログラムは、シェルに表示される文字列の長さを示します。

結論

この記事では、C言語のdlopen関数に関する情報を提供します。 dlopen 関数の簡単な紹介があります。次に、2 つの例を実装しました。この関数は、開いているライブラリを定義する識別子を返します。開いたライブラリ内の関数のアドレスは、この識別子と dlsym 関数を使用して決定されます。 dlopen を使用して既に開いているライブラリ内の関数のアドレスは、dlsym 関数を使用して見つけることができます。