linux dlopen 内存版本,dlopen函数详解

linux dlopen 内存版本,dlopen函数详解Linux提供了一套API来动态装载库。下面列出了这些API:-dlopen,打开一个库,并为使用该库做些准备。-dlsym,在打开的库中查找符号的值。-dlclose,关闭库。-dlerror,返回一个描述最后一次调用dlopen、dlsym,或dlclose的错误信息的字符串。C语言用户需要包含头文件dlfcn.h才能使用上述API。glibc还增加了两个POSIX标准中没有的API:…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

Linux提供了一套API来动态装载库。下面列出了这些API:

– dlopen,打开一个库,并为使用该库做些准备。

– dlsym,在打开的库中查找符号的值。

– dlclose,关闭库。

– dlerror,返回一个描述最后一次调用dlopen、dlsym,或dlclose的错误信息的字符串。

C语言用户需要包含头文件dlfcn.h才能使用上述API。glibc还增加了两个POSIX标准中没有的API:

– dladdr,从函数指针解析符号名称和所在的文件。

– dlvsym,与dlsym类似,只是多了一个版本字符串参数。

在Linux上,使用动态链接的应用程序需要和库libdl.so一起链接,也就是使用选项-ldl。但是,编译时不需要和动态装载的库一起链接。程序3-1是一个在Linux上使用dl*例程的简单示例。

延迟重定位(Lazy Relocation)

延迟重定位/装载是一个允许符号只在需要时才重定位的特性。这常在各UNIX系统上解析函数调用时用到。当一个和共享库一起链接的应用程序几乎不会用到该共享库中的函数时,该特性被证明是非常有用的。这种情况下,只有库中的函数被应用程序调用时,共享库才会被装载,否则不会装载,因此会节约一些系统资源。但是如果把环境变量LD_BIND_NOW设置成一个非空值,所有的重定位操作都会在程序启动时进行。也可以在链接器命令行通过使用-z now链接器选项使延迟绑定对某个特定的共享库失效。需要注意的是,除非重新链接该共享库,否则对该共享库的这种设置会一直有效。

初始化(initializing)和终止化(finalizing)函数

有时候,以前的代码可能用到了两个特殊的函数:_init和_fini。_init和_fini函数用在装载和卸载某个模块(注释14)时分别控制该模块的构造器和析构器(或构造函数和析构函数)。他们的C语言原型如下:

void _init(void);

void _fini(void);

当一个库通过dlopen()动态打开或以共享库的形式打开时,如果_init在该库中存在且被输出出来,则_init函数会被调用。如果一个库通过dlclose()动态关闭或因为没有应用程序引用其符号而被卸载时,_fini函数会在库卸载前被调用。当使用你自己的_init和_fini函数时,需要注意不要与系统启动文件一起链接。可以使用GCC选项 -nostartfiles 做到这一点。

但是,使用上面的函数或GCC的-nostartfiles选项并不是很好的习惯,因为这可能会产生一些意外的结果。相反,库应该使用__attribute__((constructor))和__attribute__((destructor))函数属性来输出它的构造函数和析构函数。如下所示:

void __attribute__((constructor)) x_init(void)

void __attribute__((destructor)) x_fini(void)

构造函数会在dlopen()返回前或库被装载时调用。析构函数会在这样几种情况下被调用:dlclose()返回前,或main()返回后,或装载库过程中exit()被调用时。

我们通过一个例子来讲解dlopen系列函数的使用和操作:

主程序:

#include

#include

#include

//申明结构体

typedef struct __test {

int i;

void (* echo_fun)(struct __test *p);

}Test;

//供动态库使用的注册函数

void __register(Test *p) {

p->i = 1;

p->echo_fun(p);

}

int main(void) {

void *handle = NULL;

char *myso = “./mylib.so”;

if((handle = dlopen(myso, RTLD_NOW)) == NULL) {

printf(“dlopen – %sn”, dlerror());

exit(-1);

}

return 0;

}

动态库:

#include

#include

//申明结构体类型

typedef struct __test {

int i;

void (*echo_fun)(struct __test *p);

}Test;

//申明注册函数原型

void __register(Test *p);

static void __printf(Test *p) {

printf(“i = %dn”, p->i);

}

//动态库申请一个全局变量空间

//这种 “.成员”的赋值方式为c99标准

static Test config = {

.i = 0,

.echo_fun = __printf,

};

//加载动态库的自动初始化函数

void _init(void) {

printf(“initn”);

//调用主程序的注册函数

__register(&config);

}

主程序编译: gcc test.c -ldl -rdynamic

动态库编译: gcc -shared -fPIC -nostartfiles -o mylib.so mylib.c

主程序通过dlopen()加载一个.so的动态库文件, 然后动态库会自动运行 _init() 初始化函数, 初始化函数打印一个提示信息, 然后调用主程序的注册函数给结构体重新赋值, 然后调用结构体的函数指针, 打印该结构体的值. 这样就充分的达到了主程序和动态库的函数相互调用和指针的相互传递.

gcc参数-rdynamic 用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪).

gcc参数 -fPIC 作用: 当使用.so等类的库时,当遇到多个可执行文件共用这一个库时, 在内存中,这个库就不会被复制多份,让每个可执行文件一对一的使用,而是让多个可执行文件指向一个库文件,达到共用. 宗旨:节省了内存空间,提高了空间利用率.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215501.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Android4.2.2启动动画前播放视频

    Android4.2.2启动动画前播放视频

    2021年11月13日
    51
  • 网页游戏设计经验谈「建议收藏」

    网页游戏设计经验谈「建议收藏」作者是网页游戏《古今东西》(www.ooplay.net)的设计者。这篇文章讲述了设计游戏3年中的感悟。 引言有这样一个故事。曾经有一段时期,地球上所有的人都是神,但是他们却无法无天,滥用神权。因此,众神之神的梵天决定,要把人的神性从他们身上取走,藏在他们永远也找不到的地方,让他们再也不能滥用自己的神权。“我们把它深埋在地下吧。”其他神说。“不,”梵天说,“因为他们会向下挖地,

    2022年6月1日
    29
  • 数据库常见面试题及答案(数据库面试常见问题)

    数据库常见面试题及答案(数据库面试常见问题)1、触发器的作用?触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。2、什么是存储过程?用什么来调用?存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在…

    2022年4月18日
    88
  • 第一个Java程序—HelloWorld[通俗易懂]

    第一个Java程序—HelloWorld[通俗易懂]工欲善其事必先利其器,在写第一个Java程序之前,需要安装JDK以及配置环境变量,具体步骤见Windows中配置Java环境变量。环境变量搭建完成了,是不是已经迫不及待想敲几行代码跑跑看?走起!1.在英文路径下创建一个记事本文件,命名为HelloWorld.java。这个文件是存放java代码的文件,称为源文件。这里是将文件类型改为java类型,并不单单是名字。这里的.java是文件类型,有的电脑上可能文件后缀名给隐藏了,虽然文件名里有.java但不是个java文件。可以点击查看,将文件扩展

    2022年7月9日
    18
  • 使用c++SFML制作月圆之夜总集篇[通俗易懂]

    使用c++SFML制作月圆之夜总集篇[通俗易懂]写在开头重新以时间线的形式整理一下去年使用c++的SFML库制作月圆之夜(游戏程序设计大作业)的开发过程,括号里面是新的补充以及对一年前自己的吐槽因为是在大二转专业后做首次接触游戏开发后才做的,当时c++学习得并不好,所以代码很乱很糟糕,许多思路也不是很清晰,完全是摸爬滚打混过来的,最后也有很多bug,不过还是一次很有收获的经历当时也尝试着学习用游戏引擎做游戏,还觉得游戏引擎太难用了,现在想想游戏引擎是真的方便,真香2020年4月6日昨天做完扫雷后,思考了一下游戏程序设计的课程设计应该做什么。虽然

    2025年7月1日
    6
  • django初探-创建简单的博客系统(二)建议收藏

    显示博客信息将博客内容保存到数据库还不是发布博客的终极目的,博客一定要显示出来,显示博客信息的基本知识如下图:显示文章标题获取数据当我们在./blog/models.py中创建了数据模型后,D

    2021年12月19日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号