使用特殊句柄 RTLD_NEXT,应用程序可在符号范围内查找下一个符号。例如,如果应用程序 prog 包含以下代码片段:
if ((fptr = (int (*)())dlsym(RTLD_NEXT, "foo")) == NULL) { (void) printf("dlsym: %s\n", dlerror()); exit (1); } return ((*fptr)()); |
则会在与 prog 关联的共享库(在此情况下为 /lib/libc.so.1)中搜索 foo。如果此代码片段包含在图 3–1 中显示的示例的文件 B.so.1 中,则仅会在 C.so.1 中搜索 foo。
使用 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.so.1 可插入到 malloc(3C) 通常所在的系统库 /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 .......... |
使用任何插入方法的用户在处理任何可能的递归时都必须小心。前面的示例使用 sprintf(3C),而不是直接使用 printf(3C) 来格式化诊断消息,以避免由于 printf(3C) 可能使用 malloc(3C) 而导致产生递归。
在动态可执行文件或预装入的目标文件中使用 RTLD_NEXT,可提供可预测的插入方法。在一般目标文件依赖项中使用此方法时应该十分小心,因为目标文件的实际装入顺序有时无法预测。