当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > linux开发:linux内存加载动态库?

linux开发:linux内存加载动态库? 时间:2019-03-27      来源:华清远见

1 Linux应用程序可能会使用到两种函数库,一种静态库、一种动态库,静态库以.a为扩展名,动态库以.so为扩展名。二者都使用广泛。

2 动态库和静态库的基本概念?

静态库,是在可执行程序连接时就已经加入到执行码中,在物理上成为执行程序的一部分;使用静态库编译的程序运行时无需该库文件支持,哪里都可以用,但是生成的可执行文件较大。动态库,是在可执行程序启动时加载到执行程序中,可以被多个可执行程序共享使用。使用动态库编译生成的程序相对较小,但运行时需要库文件支持,如果机器里没有这些库文件就不能运行。

3 如何使用动态库?

动态库也叫共享库,如果在程序连接时使用共享库,就必须在运行时找到共享库的位置。Linux的可执行程序在执行的时候默认是先搜索/lib和/usr/lib这两个目录,然后按照/etc/ld.so.conf里面的配置搜索绝对路径。同时,linux也提供了环境变量LD_LIBRARY_PATH供用户选择使用,用户可以通过它来查找默认路径之外的其他路径,如要查找/work/lib路径,你可以在/etc/rc.d/rc.local或其他系统启动后即可执行到的脚本文件中添加如下语句:LD_LIBRARY_PATH=/work/lib:$(LD_LIBRARY_PATH)。并且LD_LIBRARY_PATH路径优先于系统默认路径之前查找。

不过LD_LIBRARY_PATH的设定作用是全局的,过多的使用可能会影响到其他应用程序的运行,所以多用在调试。

4 库的连接路经和运行路经

现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开,用户可以通过-L指定连接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。比如我们做嵌入式移植时#arm-linux-gcc $(CFLAGS) –o target –L/work/lib/zlib/ -llibz-1.2.3 (work/lib/zlib下是交叉编译好的zlib库),将target编译好后我们只要把zlib库拷贝到开发板的系统默认路径下即可。或者通过- rpath(或-R )、LD_LIBRARY_PATH指定查找路径

5 动态库的加载使用?

基本上每个linux程序都至少会用一个动态库,查看某个程序使用了那些动态库,使用命令ldd查看

如:#ldd /bin/ls (查看系统中ls用到的动态库)

#ldd main (查看自定义main用到的动态库)

#ldd -u main(查看自定义main中无用的动态库)

#strace ./main(查看程序启动时加载的所有动态库)

Linux程序启动时加载的库有默认的库也有显式手动连接的库

1 默认:编译代码时不手动连接额外库,那么在代码中使用到库函数时会在运行时自动加载连接需要的库。

#gcc -o main main.c

#ldd main

linux-vdso.so.1 => (0x00007fffa1b6d000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff4fde52000)

/lib64/ld-linux-x86-64.so.2 (0x00007ff4fe230000)

2 手动:编译代码时手动添加额外的库,那么在程序运行时,既要加载默认的库,还要加载手动添加的库。加载的库多了,会影响程序启动的速度。

#gcc -o main1 -lm -lrt main.c (编译时手动连接数学库、线程库)

#ldd main1

linux-vdso.so.1 => (0x00007fff88770000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f993a0cc000)

/lib64/ld-linux-x86-64.so.2 (0x00007f993a4aa000)

#strace ./main1

从程序运行中可以看出main1运行时即加载了默认库,也加载了手动指定的库(在此手动指定的数学库、线程库是代码不需要的,但在程序运行时也加载了),会影响整个程序的加载速度。

大家知不知道linux从程序(program或对象)变成进程(process或进程),要经过哪些步骤呢,简单的说分三步:

1、fork进程,在内核创建进程相关内核项,加载进程可执行文件;

2、查找依赖的so,一一加载映射虚拟地址

3、初始化程序变量。

可以看到,第二步中dll依赖越多,进程启动越慢,并且发布程序的时候,有这些链接但没有使用的so,同样要一起跟着发布,否则进程启动时候,会失败,找不到对应的so。所以我们不能像上面那样,把一些毫无意义的so链接进来,浪费资源。

6 关于Linux程序连接so有两种方式:隐式和显示

所谓显示就是程序主动调用dlopen打开相关so;首先,dlopen的so使用ldd是查看不到的。其次,使用dlopen打开的so并不是在进程启动时候加载映射的,而是当进程运行到调用dlopen代码地方才加载该so,也就是说,如果每个进程显示链接a.so;但是如果发布该程序时候忘记附带发布该a.so,程序仍然能够正常启动,甚至如果运行逻辑没有触发运行到调用dlopen函数代码地方。该程序还能正常运行,即使没有a.so. 既然显示加载这么多优点,那么为什么实际生产中很少码农使用它呢, 主要原因还是起使用不是很方便,需要开发人员多写不少代码。所以不被大多数码农使用,还有一个重要原因应该是能提前发现错误,在部署的时候就能发现缺少哪些so,而不是等到实际上限运行的时候才发现缺东少西。

上一篇:嵌入式学习:开源与闭源

下一篇:linuxtrap脚本信号捕获命令的使用

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2018 北京华清远见科技发展有限公司 版权所有 ,京ICP备16055225号,京公海网安备11010802025203号