【动态库加载方式】动态库的两种加载方式简析

动态库加载方式

这里说的so就是动态库 ,加载方式分为两种

  • explicit: dlopen显式拉起

  • implicit: 在链接的时候指定so的依赖

1. 显式加载:

1.1 dlopen

dlopen之后会获得一个句柄,就是这个so在内存中的加载地址

  • 同一个进程dlopen同一个so,内存中不会增加副本,只会增加dlopen的指针计数(配合dlclose使用)

  • 可以用于热加载,用于实现c语言的多态

  • dlopen同一个so,不会增加句柄计数,所以一个进程里面忘记dlclose一次就会增加一个句柄泄漏

  • dlopen之后如果立即dlclose,那么下一次dlopen获得的内存地址是一样的(参考实验)

1.2 dlsym

dlsym两种使用方法:

  1. 使用dlopen获得的handle,在指定的so里面寻找符号

  2. 不指定dlopen的句柄,在依赖的so里面全局搜索

    1. RTLD_NEXT: 按照链接顺序,找到符号表第一次出现的地方,可以用于实现preload机制

    2. RTLD_DEFAULT:直接全局搜索符号表第一次出现的地方

1.3 dlclose

  • dlclose用于unload。每次dlclose都会导致指针技术-1, 计数为0的时候,就会unload 当前动态库

    • 隐式load的动态库,也会增加计数

2. 隐式加载

一般使用ld或者cmakelist里面指定的方式,隐式制定依赖关系,在加载一个so的时候,会同时把所有的依赖so都加载到内存里面

  • 优点:编码方便,不容易导致句柄泄漏,大部分情况用隐示加载

  • 缺点:不够灵活,耦合严重,实现松耦合的目标,不可以使用隐式加载

3. 实验

3.1实验步骤

  • 代码地址:https://github.com/GJStar/programmer
git clone git@github.com:GJStar/programmer.git
cd programmer/shared_object_load/
make all
./demo
#include <stdio.h>
#include <dlfcn.h>

typedef void (* func_t)();
const char* g_relative_path = "./libsym.so";

/* lab3:dlopen/dlclose之后,下一次打开so还是在同一个内存地址 */
void test_open_close()
{

	void *handle = dlopen(g_relative_path, RTLD_LAZY);
	if (!handle) {
		printf("%s\n", dlerror());
		return;
	}

	printf("handle fisrt addr:0x%llx\n", (unsigned long long)handle);
	func_t func = dlsym(handle, "sym");
	dlclose(handle);

	/* 第二次打开so */
	handle = dlopen(g_relative_path, RTLD_LAZY);
	if (!handle) {
		printf("%s\n", dlerror());
		return;
	}

	printf("handle second addr:0x%llx\n", (unsigned long long)handle);
	func(); // 这种是违规操作,这里是为了验证两次内存空间一模一样
	dlclose(handle);

	handle = dlopen("./libadd.so", RTLD_LAZY);
	if (!handle) {
		printf("%s\n", dlerror());
		return;
	}

	printf("handle dlopen libadd.so addr:0x%llx\n", (unsigned long long)handle);


	void *handle2 = dlopen(g_relative_path, RTLD_LAZY);
	if (!handle2) {
		printf("%s\n", dlerror());
		return;
	}

	printf("handle third addr:0x%llx\n", (unsigned long long)handle2);
	dlclose(handle);
	dlclose(handle2);
	return;
}

int main()
{
	// 测试不同情况查下dlopen之后的效果
	test_open_close();
	return 0;
}

3.2实验结果

handle fisrt addr:0x560325bf12c0
handle second addr:0x560325bf12c0
I'm sym1
handle dlopen libadd.so addr:0x560325bf12c0
handle third addr:0x560325bf1d50
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值