linux 加载so库

本文详细介绍了Linux下动态链接库(DLL)的加载方式,包括RTLD_LAZY、RTLD_NOW、RTLD_GLOBAL和RTLD_LOCAL的不同作用。探讨了函数导出的属性设置方法,如visibility属性,并通过实例展示了如何使用readelf、objdump和nm工具来查看库的符号作用域及导出情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//RTLD_LAZY:在dlopen返回前,对于动态库中的没有定义的符号不运行解析(仅仅对函数引用有效。对于变量引用总是马上解析)。
//RTLD_NOW: 须要在dlopen返回前。解析出全部没有定义符号,假设解析不出来。在dlopen会返回NULL,错误为:: undefined symbol: xxxx.......
//RTLD_GLOBAL:动态库中定义的符号可被其后打开的其他库解析。
//RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其他库重定

void *handle = dlopen(filename, RTLD_LOCAL | RTLD_LAZY);
const char *version = (const char *)dlsym(handle, "version");
void (*module_init)()= (void(*)())dlsym(handle, "module_init");
if(!module_init)
{
    fprintf(stderr, "%s MediaServiceInit >>%s\n", name, dlerror());
    dlclose(handle);
}
module_init();

函数导出:

__attribute__ ((visibility ("default")))

__attribute__ ((visibility ("hidden")))

库查看(符号作用域):

#读取elf文件
readelf -s libtest.so

43: 00000000000006c6    19 FUNC    LOCAL  DEFAULT   12 test1
61: 00000000000006b3    19 FUNC    GLOBAL DEFAULT   12 test

#查看符号表
objdump  -t libtest.so

00000000000006c6 l     F .text  0000000000000013              test1
00000000000006b3 g     F .text  0000000000000013              test

#查看动态符号表(只显示g d D DF),g代表GLOBAL(global)导出的符号,可以被查找并调用
objdump  -T

00000000000006b3 g    DF .text  0000000000000013  Base        test

#使用nm查看T(导出的)和t (没导出)
nm libtest.so

00000000000006b3 T test
00000000000006c6 t test1

ar 用于打包成静态文件.a

编译:

主程序编译需要:

-Wl,--export-dynamic -fvisibility=hidden

  SO库编译

gcc -fvisibility=hidden -fPIC -shared libtest.c -o libtest.so

 

### Linux 动态加载 SO 的详细过程 在 Linux 中,动态加载共享对象(SO 文件)通常通过 `dlopen` 函数来实现。此函数允许程序在运行时打开并访问共享文件。 #### 使用 dlopen 加载共享 当调用 `dlopen` 来加载一个 `.so` 文件时,该函数会返回指向已加载的一个句柄。如果失败,则返回 NULL 并设置错误信息[^5]。 ```c void* handle; handle = dlopen("./libexample.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); } ``` 这里展示了如何处理可能发生的错误情况,并打印出错原因。 #### 获取符号地址 一旦成功打开了共享,就可以使用 `dlsym` 函数获取特定符号(通常是函数名或变量名)对应的内存地址: ```c int (*func)(const char*); *(void **)(&func) = dlsym(handle, "function_name"); char *error; if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); } ``` 这段代码尝试检索名为 `"function_name"` 的函数指针;同样地,在遇到问题时提供反馈。 #### 关闭共享连接 完成操作之后应当调用 `dlclose` 来关闭与共享之间的联系,释放资源: ```c dlclose(handle); ``` 这一步骤对于防止内存泄漏非常重要。 #### 设置环境变量 LD_LIBRARY_PATH 为了让应用程序能够找到自定义路径下的 .so 文件,可以在启动前临时修改 `LD_LIBRARY_PATH` 环境变量或将新位置加入到 `/etc/ld.so.conf.d/` 下配置文件中以便永久生效[^3]。 例如: ```bash export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH ``` 这样做的目的是让动态链接器知道去哪里查找所需的依赖项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值