多平台加载动态链接库总结
1、Linux, SunOS, Solaris, IRIX, FreeBSD,NetBSD, AIX 4.2, HPUX 11,和其它类Unix系统
头文件:#include <dlfcn.h>
加载:void *dlopen(const char *filename, int flag);
示例:void* hnd = dlopen(path,RTLD_NOW) path是动态库路径,void*是加载后的句柄
flag的类别:
RTLD_LAZY:在dlopen返回前,对于动态库中存在的未定义的变量(如外部变量extern,也可以是函数)不执行解析,就是不解析这个变量的地址。
RTLD_NOW:与上面不同,他需要在dlopen返回前,解析出每个未定义变量的地址,如果解析不出来,在dlopen会返回NULL
RTLD_GLOBAL:它的含义是使得库中的解析的定义变量在随后的其它的链接库中变得可以使用。
RTLD_LOCAL
调用:void* dlsym(void* handle,const char* symbol)
示例:void* func = dlsym(hnd,"func")执行后,func里存的就是动态库里名字为func的函数或全局变量的地址
卸载:int dlclose (void *handle);
只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
2、windows
头文件:#include <windows.h>
加载:HINSTANCE lib = LoadLibraryA(path);
调用:GetProcAddress((HINSTANCE)lib, sym);
卸载:FreeLibrary((HINSTANCE)lib);
3、mac os
头文件:#include <mach-o/dyld.h>
加载: void* hnd = NULL;
NSObjectFileImage img;
NSObjectFileImageReturnCode ret;
if(!_dyld_present())
{
return;
}
if(NSObjectFileImageSuccess == NSCreateObjectFileImageFromFile(path, &img))
{
NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
NSDestroyObjectFileImage(img);
hnd = mod;
}
调用:NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym);
void* func = NSAddressOfSymbol(nss);
卸载:NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
///
动态链接库构造和析构功能函数实现
windows里的话会自动调用下面的函数
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
但linux类系统里不会这么调用,而是会调_init和_finit,
但这两个函数都是gcc占用的,它们会做初始化全局变量等操作,我们
不能直接改写,只能通过下面的方式来实现需求。
1、利用c++类的构造和析构函数实现
class module
{
module()
{
//do init here
}
~module()
{
//do finit here
}
};
static module g_module;
2、利用gcc扩展实现
__attribute((constructor)) void module_init()
{
//do init here
}
__attribute((destructor)) void module_finit()
{
//do finit here
}
1、Linux, SunOS, Solaris, IRIX, FreeBSD,NetBSD, AIX 4.2, HPUX 11,和其它类Unix系统
头文件:#include <dlfcn.h>
加载:void *dlopen(const char *filename, int flag);
示例:void* hnd = dlopen(path,RTLD_NOW) path是动态库路径,void*是加载后的句柄
flag的类别:
RTLD_LAZY:在dlopen返回前,对于动态库中存在的未定义的变量(如外部变量extern,也可以是函数)不执行解析,就是不解析这个变量的地址。
RTLD_NOW:与上面不同,他需要在dlopen返回前,解析出每个未定义变量的地址,如果解析不出来,在dlopen会返回NULL
RTLD_GLOBAL:它的含义是使得库中的解析的定义变量在随后的其它的链接库中变得可以使用。
RTLD_LOCAL
调用:void* dlsym(void* handle,const char* symbol)
示例:void* func = dlsym(hnd,"func")执行后,func里存的就是动态库里名字为func的函数或全局变量的地址
卸载:int dlclose (void *handle);
只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
2、windows
头文件:#include <windows.h>
加载:HINSTANCE lib = LoadLibraryA(path);
调用:GetProcAddress((HINSTANCE)lib, sym);
卸载:FreeLibrary((HINSTANCE)lib);
3、mac os
头文件:#include <mach-o/dyld.h>
加载: void* hnd = NULL;
NSObjectFileImage img;
NSObjectFileImageReturnCode ret;
if(!_dyld_present())
{
return;
}
if(NSObjectFileImageSuccess == NSCreateObjectFileImageFromFile(path, &img))
{
NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
NSDestroyObjectFileImage(img);
hnd = mod;
}
调用:NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym);
void* func = NSAddressOfSymbol(nss);
卸载:NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
///
动态链接库构造和析构功能函数实现
windows里的话会自动调用下面的函数
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
但linux类系统里不会这么调用,而是会调_init和_finit,
但这两个函数都是gcc占用的,它们会做初始化全局变量等操作,我们
不能直接改写,只能通过下面的方式来实现需求。
1、利用c++类的构造和析构函数实现
class module
{
module()
{
//do init here
}
~module()
{
//do finit here
}
};
static module g_module;
2、利用gcc扩展实现
__attribute((constructor)) void module_init()
{
//do init here
}
__attribute((destructor)) void module_finit()
{
//do finit here
}