函数 描述
#include<dlfcn.h>头文件定义如下四个函数
dlopen 使对象文件可被程序访问
dlsym 获取执行了 dlopen 函数的对象文件中的符号的地址
dlerror 返回上一次出现错误的字符串错误
dlclose 关闭目标文件
dlopen函数返回一个句柄,该句柄用于后续的 API 调用。
dlopen的原型为:#include<dlfcn.h>
void *dlopen( const char *file, int mode );
该过程首先是调用 dlopen,提供要访问的文件对象和模式。调用 dlopen 的结果是稍候要使用的对象的句柄。mode 参数通知动态链接器何时执行再定位。有两个可能的值。第一个是 RTLD_NOW,它表明动态链接器将会在调用 dlopen 时完成所有必要的再定位。第二个可选的模式是 RTLD_LAZY,它只在需要时执行再定位。这是通过在内部使用动态链接器重定向所有尚未再定位的请求来完成的。这样,动态链接器就能够在请求时知晓何时发生了新的引用,而且再定位可以正常进行。后面的调用无需重复再定位过程。
还可以选择另外两种模式,它们可以按位 OR 到 mode 参数中。RTLD_LOCAL 表明其他任何对象都无法使加载的共享对象的符号用于再定位过程。如果这正是您想要的的话(例如,为了让共享的对象能够调用原始进程映像中的符号),那就使用 RTLD_GLOBAL 吧。
dlopen 函数还会自动解析共享库中的依赖项。这样,如果您打开了一个依赖于其他共享库的对象,它就会自动加载它们。
有了 ELF 对象的句柄,就可以通过调用 dlsym 来识别这个对象内的符号的地址了。该函数采用一个符号名称,如对象内的一个函数的名称。
返回值为对象符号的解析地址:
void *dlsym( void*restrict handle, const char *restrict name );
如果调用该 API 时发生了错误,可以使用 dlerror 函数返回一个表示此错误的人类可读的字符串。该函数没有参数,它会在发生前面的错误时返回一个字符串,在没有错误发生时返回 NULL:char *dlerror();
最后,如果无需再调用共享对象的话,应用程序可以调用 dlclose 来通知操作系统不再需要句柄和对象引用了。它完全是按引用来计数的,所以同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中)。
任何通过已关闭的对象的 dlsym 解析的符号都将不再可用。
char *dlclose( void *handle );
示例:
dltest.c:
- #include <stdio.h>
- int printStr(char *str)
- {
- printf("***************************\n");
- printf("%s\n", str);
- printf("===========================\n");
- return 0;
- }
dlmain.c
- #include <stdio.h>
- #include <dlfcn.h>
- #include <unistd.h>
- typedef int (*FUNC)(char*);
- int main(int argc, char *argv[])
- {
- char outStr[20] = {"test dl."};
- char *error = NULL;
- void *dlHandle = NULL;
- FUNC pFunc;
- dlHandle = dlopen("./dltest.so", RTLD_LAZY);
- if(dlHandle == NULL)
- {
- printf("dlHandle is null\n");
- return -1;
- }
- pFunc = (FUNC)dlsym(dlHandle, "printStr");
- if((error = dlerror()) != NULL)
- {
- printf("dlsym error(%s).\n", error);
- return -1;
- }
- pFunc(outStr);
- dlclose(dlHandle);
- return 0;
- }
/* Makefile */
all:
gcc -o dltest.o -c dltest.c
gcc -fPIC -shared dltest.o -o dltest.so
gcc -rdynamic -ldl dlmain.c -o dlmain
注:选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中,
目的是能够通过使用 dlopen 来实现向后跟踪。
选项 -ldl 表明一定要将 dllib 链接于该程序,
不然编译器会报dlopen、dlsym、dlerror、dlclose等找不到。
–fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
–shared:指明编译成动态库。
注:dlopen函数的第一个参数,若非系统特定目录的动态库,则必须带上目录路径,否则运行时会找不到动态库