句柄和对象引用了.它完全是按引用来计数的, 同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中).任何通过已关闭的对象的 dlsym 解析的符号都将不再可用.
char *dlclose( void *handle );
|
动态加载示例
了解了 API 之后,下面让我们来看一看 DL API 的例子.在这个应用程序中,您主要实现了一个 shell,它允许操作员来指定库、函数和参数.换句话说,也就是用户能够指定一个库并调用该库(先前未链接于该应用程序的)内的任意一个函数. 使用 DL API 来解析该库中的函数,然后使用用户定义的参数(用来发送结果)来调用它.清单 2 展示了完整的应用程序.
清单 2. 使用 DL API 的 Shell
#include <stdio.h> #include <dlfcn.h> #include <string.h>
#define MAX_STRING 80
void invoke_method( char *lib, char *method, float argument ) { void *dl_handle; float (*func)(float); char *error;
/* Open the shared object */ dl_handle = dlopen( lib, RTLD_LAZY ); if (!dl_handle) { printf( "!!! %sn", dlerror() ); return; }
/* Resolve the symbol (method) from the object */ func = dlsym( dl_handle, method ); error = dlerror(); if (error != NULL) { printf( "!!! %sn", error ); return; }
/* Call the resolved method and print the result */ printf(" %fn", (*func)(argument) );
/* Close the object */ dlclose( dl_handle );
return; }
int main( int argc, char *argv[] ) { char line[MAX_STRING 1]; char lib[MAX_STRING 1]; char method[MAX_STRING 1]; float argument;
while (1) {
printf("> ");
line[0]=0; fgets( line, MAX_STRING, stdin);
if (!strncmp(line, "bye", 3)) break;
sscanf( line, "%s %s %f", lib, method, &argument);
invoke_method( lib, method, argument );
}
}
|
要构建这个应用程序,需要通过 GNU Compiler Collection(GCC)使用如下的编译行.选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪).-ldl 表明一定要将 dllib 链接于该程序.
gcc -rdynamic -o dl dl.c -ldl
|
再回到 清单 2,main 函数仅充当解释器,解析来自输入行的三个参数(库名、函数名和浮点参数).如果出现 bye 的话,应用程序就会退出.否则的话,这三个参数就会传递给使用 DL API 的 invoke_method 函数.
调用 dlopen 来访问目标文件.如果返回 NULL 句柄,表示无法找到对象,过程结束.否则的话,将会得到对象的一个句柄,可以进一步询问对象.然后使用 dlsym API 函数,尝试解析新打开的对象文件中的符号.您将会得到一个有效的指向该符号的指针,或者是得到一个 NULL 并返回一个错误.
在 ELF 对象中解析了符号后,下一步就只需要调用函数.要注意一下这个代码和前面讨论的动态链接的差别.在这个例子中,您强行将目标文件中的符号地址用作函数指针,然后调用它.而在前面的例子是将对象名作为函数,由动态链接器来确保符号指向正确的位置.虽然动态链接器能够为您做所有麻烦的工作,但这个方法会让您构建出极其动态的应用程序,它们可以再运行时被扩展.
调用 ELF 对象中的目标函数后,通过调用 dlclose 来关闭对它的访问.
清单 3 展示了一个如何使用这个测试程序的例子.在这个例子中, 编译程序而后执行它.接着调用了 math 库(libm.so)中的几个函数.完成演示后,程序现在能够用动态加载来调用共享对象(库)中的任意函数了.这是一个很强大的功能,通过它还能够给程 |