特別なハンドル RTLD_NEXT を使用すると、アプリケーションは、シンボルの範囲内で次のシンボルの場所を見つけることができます。たとえば、アプリケーション prog に次のようなコードフラグメントが組み込まれているとします。
if ((fptr = (int (*)())dlsym(RTLD_NEXT, "foo")) == NULL) { (void) printf("dlsym: %s\n", dlerror()); exit (1); } return ((*fptr)()); |
この場合 foo は、prog に関連した共有オブジェクト内で、この場合は /usr/lib/libdl.so.1 の次に /usr/lib/libc.so.1 が検索されます。このコードフラグメントが、図 3–1 の例で示すように、ファイル B.so.1 に組み込まれている場合は、foo は関連する共有オブジェクト C.so.1 の中だけで検索されます。
RTLD_NEXT を使用することによって、シンボル割り込みを活用できます。たとえば、オブジェクト内の関数は、オブジェクトの前に付けて割り込みでき、これにより、元の関数の処理を補強できます。たとえば、次のコードフラグメントを共有オブジェクト malloc.so.1 内に配置します。
#include <sys/types.h> #include <dlfcn.h> #include <stdio.h> void * malloc(size_t size) { static void * (* fptr)() = 0; char buffer[50]; if (fptr == 0) { fptr = (void * (*)())dlsym(RTLD_NEXT, "malloc"); if (fptr == NULL) { (void) printf("dlopen: %s\n", dlerror()); return (0); } } (void) sprintf(buffer, "malloc: %#x bytes\n", size); (void) write(1, buffer, strlen(buffer)); return ((*fptr)(size)); } |
この共有オブジェクトを、malloc(3C) が通常存在するシステムライブラリ /usr/lib/libc.so.1 の前に割り込ませることができます。こうすれば、malloc() に対するすべての呼び出しは、本来の関数が呼ばれて割り当てを行う前に、割り込まれます。
$ cc -o malloc.so.1 -G -K pic malloc.c $ cc -o prog file1.o file2.o ..... -R. malloc.so.1 $ prog malloc: 0x32 bytes malloc: 0x14 bytes .......... |
あるいは、次のように入力しても、上記と同じ割り込みを実行できます。
$ cc -o malloc.so.1 -G -K pic malloc.c $ cc -o prog main.c $ LD_PRELOAD=./malloc.so.1 prog malloc: 0x32 bytes malloc: 0x14 bytes .......... |
割り込みテクニックを使用する場合、反復する可能性がある処理には注意が必要です。前の例では、printf(3C) を直接使用する代わりに sprintf(3C) を使用して診断メッセージを形成し、printf(3C) が malloc(3C) を使用する可能性があることによる反復を防いでいます。
動的実行プログラムまたはあらかじめ読み込まれたオブジェクト内で RTLD_NEXT を使用することにより、予測可能で有用な割り込みテクニックが使用できます。ただし、このテクニックを汎用オブジェクトの依存関係内で使用する場合には、実際に読み込まれる順番が必ず予測できるとは限らないため、注意が必要です。