c程序加载动态库

c语言程序动态加载动态库

参考来源

动态加载动态库,一般用于模块扩展或者更换动态库。

1. dlopen用法

  1. 包含头文件#include<dlfcn.h>

  2. 函数定义void * dlopen(const char* pathName, int mode);
    pathName指的是db文件或listDB.so文件在实机环境中的位置,mode指的是打开数据库的模式。
    modelinux下,按功能有以下几种

    • 解析方式:
      • RTLD_LAZY:暂缓决定,在dlopen返回前,对于动态库中的未定义的符号不执行解析(只对函数引用有效,对于变量引用总是立即解析)
      • RTLD_NOW:立即决定,在dlopen返回前,解析出所有未定义的符号,如果解析不出来,在dlopen会返回NULL,错误为undefined symbol:XXX...
    • 作用范围:
      • RTLD_GLOBAL: 动态库中定义的符号可被其后打开的其他库重定位
      • RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其他库重定位。如果没有指明是RTLD_GLOBAL还是RTLD_LOCAL,那么默认是RTLD_LOCAL
    • 作用方式:
      • RTLD_NODELETE:在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量。这个flag不是POSIX-2001标准。
      • RTLD_NOLOAD: 不加载库,可用于测试库是否已经加载(dlopen()返回NULL说明未加载,否则说明加载),也可用于改变已加载库的flag,如:先前加载库的flagRTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)flag将变成RTLD_GLOBAL.这个flag不是POSIX-2001标准
      • RTLD_DEEPBIND:在搜索全局符号前先搜索库内的符号,避免同名符号的冲突,这个flag不是POSIX-2001标准
  3. 返回值void*,如果成功则返回引用这个数据库的句柄,如果失败则返回NULL,编译时要加入 -ldl(指定dl库):

    ey:gcc test.c -o test -ldl
    

2. dlsym用法

  1. 包含头文件#include<dlfcn.h>
  2. 函数定义void *dlsym(void *handle, const char* symbol);
    handle是使用dlopen函数之后返回的句柄,symbol是要求获取的函数的名称,函数,返回值是void*,指向函数的地址,供调用使用。

dlsymdlopen的以如下例子解释:

#include<dlfcn.h>

void * handle = dlopen("./testListDB.so", RTLD_LAZY);

如果createListDB函数定义为:

int32_t createListDB(std::string);

那么dlsym的用法则为;

int32_t  (*create_listDB)(std::string) = reinterpret_cast<int32_t (*)(std::string)>(dlsym(handle, "createListDB"))

createListDB库函数的定义要用extern来声明,这样在主函数中才能通过createListDB来查找函数。

3. dlerror和dlclose用法

  1. dlclose():

    • 包含头文件#include<dlfcn.h>
    • 函数定义int dlclose(void *handle)
      dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
  2. dlerror():

    • 包含头文件#include<dlfcn.h>
    • 函数定义const char* dlerror(void);
      当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

4. 例子

动态库testlib.so:

#include <stdio.h>

extern void testlib(void);

void testlib(void)
{
	printf("printf : testlib.\n");
}
gcc testlib.c -o testlib.o -c -fPIC
gcc testlib.o -shared -o libtestlib.so

程序test.c:

#include <dlfcn.h>
#include <stdio.h>

typedef void (*ex_fn)(void);

int main(void)
{
	void* ex_lib = dlopen("./libtestlib.so", RTLD_LAZY);

	if (!ex_lib)
	{
		printf("error : %s\n", dlerror());
		return -1;
	}

	ex_fn ex_test = (ex_fn)dlsym(ex_lib, "testlib");

	if (!ex_test)
	{
		printf("error : %s\n", dlerror());
		dlclose(ex_lib);
		return -1;
	}

	ex_test();

	dlclose(ex_lib);

	return 0;
}
gcc test.c -o test -ldl

运行:

./test
printf : testlib.
posted @ 2020-05-16 13:47  wotsen  阅读(538)  评论(0)    收藏  举报