1、#ifndef STR_OUT_H#define STR_OUT_Hextern “C“ void str_out(const char* str); #endif#include #include “str_out.h“void str_out( const char* str )printf( “%sn“, str );#include #include / dlopen、dlsym、dlerror、dlclose 的头文件#include #include “str_out.h“/ 此例为动态加载动态库,Makefile 中会提到静态如何关联加载int main()typedef voi
2、d (*STROUT)(const char*);void * hDynamicLib = 0;STROUT fpStrOut = 0;/ 动态加载动态库名字可以不用前缀 lib,静态则一定要加hDynamicLib = dlopen(“/home/nsc/document/testpro/staticlib/str_out.so“, RTLD_LAZY);if (0 != hDynamicLib)fpStrOut = (STROUT)dlsym(hDynamicLib, “str_out“);char *szErrInfo = dlerror();if (0 = szErrInfo)fpSt
3、rOut(“Youre success again!n“); elseprintf(“%sn“, szErrInfo); dlclose(hDynamicLib);elseprintf(“error: load dynamic library failed!n“); return 0;/ * Makefile */tdynamicload : main.c str_out.sog+ -rdynamic -ldl main.c -o tdynamicload注:选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中,目的是能够通过使用 dlopen 来实现向后跟踪。选项 -ldl
4、表明一定要将 dllib 链接于该程序,不然编译器会报 dlopen、dlsym、dlerror、dlclose 等找不到。str_out.so : str_out.c str_out.hg+ -c str_out.c -o str_out.og+ -Wall -W -shared -fPIC str_out.o -o str_out.so注:由以上命令生成动态库 str_out.so,为了可以静态加载动态库,则其动态库命名方式为“lib*.so.*” 。在这个命名方式中,第一个*表示动态链接库的库名,第二个*通常表示该动态库的版本号,也可以没有版本号。fPIC:表示编译为位置独立的代码,不用
5、此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。shared:指明编译成动态库。函数 描述dlopen 使对象文件可被程序访问dlsym 获取执行了 dlopen 函数的对象文件中的符号的地址dlerror 返回上一次出现错误的字符串错误dlclose 关闭目标文件该过程首先是调用 dlopen,提供要访问的文件对象和模式。调用 dlopen 的结果是稍候要使用的对象的句柄。mode 参数通知动态链接器何时执行再定位。有两个可能的值。第一个是 RTLD_NOW,它表明动态链接器将会在调用 dlopen 时完成所有必要的再
6、定位。第二个可选的模式是 RTLD_LAZY,它只在需要时执行再定位。这是通过在内部使用动态链接器重定向所有尚未再定位的请求来完成的。这样,动态链接器就能够在请求时知晓何时发生了新的引用,而且再定位可以正常进行。后面的调用无需重复再定位过程。还可以选择另外两种模式,它们可以按位 OR 到 mode 参数中。RTLD_LOCAL 表明其他任何对象都无法使加载的共享对象的符号用于再定位过程。如果这正是您想要的的话(例如,为了让共享的对象能够调用原始进程映像中的符号) ,那就使用 RTLD_GLOBAL 吧。dlopen 函数还会自动解析共享库中的依赖项。这样,如果您打开了一个依赖于其他共享库的对象
7、,它就会自动加载它们。函数返回一个句柄,该句柄用于后续的 API 调用。dlopen 的原型为:#include void *dlopen( const char *file, int mode );有了 ELF 对象的句柄,就可以通过调用 dlsym 来识别这个对象内的符号的地址了。该函数采用一个符号名称,如对象内的一个函数的名称。返回值为对象符号的解析地址:void *dlsym( void *restrict handle, const char *restrict name );如果调用该 API 时发生了错误,可以使用 dlerror 函数返回一个表示此错误的人类可读的字符串。该函数没有参数,它会在发生前面的错误时返回一个字符串,在没有错误发生时返回 NULL:char *dlerror();最后,如果无需再调用共享对象的话,应用程序可以调用 dlclose 来通知操作系统不再需要句柄和对象引用了。它完全是按引用来计数的,所以同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中) 。任何通过已关闭的对象的 dlsym 解析的符号都将不再可用。char *dlclose( void *handle );