Linux共享库概述

共享库是一种将库函数打包成一个单元使之能够在运行时被多个进程共享的技术 。 这种技术能够节省磁盘空间和RAM 。
在继续阐述共享库之前 , 先来说说静态库 , 它是比共享库更早的存在 。 静态库也称为归档文件 , 它的作用就是将一组经常被用到的目标文件组织进单个库文件 , 这样以来 , 就可以使用它来构建多个可执行程序 , 并且在构建各个应用程序的时候无需重新编译原来的源代码 。
从以上的描述中 , 可以看出 , 静态库必须和可执行文件一起被连接进目标文件中 , 这样的话 , 不同的可执行程序使用了相同的目标模块时 , 每个可执行程序都有自己的一份静态库副本 , 这样做有以下几个缺点:

  • 存储同一目标模块会浪费磁盘空间 , 并且实际上浪费的空间还是很大的 。
  • 如果使用了同一模块的几个不同的可执行程序在同一时刻运行 , 那么每个程序会独立地在虚拟内存中保存一份目标模块的副本 , 从而提高了系统中虚拟内存的使用量 。
  • 若是需要修改静态库中的错误 , 那么需要重新生成静态库 , 再链接合并到目标文件中 。
每一种新生事物的出现都是为了解决之前已经存在的问题 , 所以这里就引出了动态库 , 它就是来解决以上这些问题的:
  • 共享库的关键思想就是目标模块的单个副本由所有需要这些模块的程序共享 , 目标模块不会被复制到链接过的可执行文件中 , 而是 , 当第一个需要共享库的木块的程序启动时 , 库的单个副本就会在运行时被加载进内存 。 当后面使用同一共享库的其他程序启动时 , 它们会使用已经加载进内存的库的副本 。 使用共享库 , 就意味着可执行程序需要的磁盘空间和虚拟内存更少了 , 这就解决了一个问题 。
  • 由于目标模块没有被复制进可执行文件中 , 而是在共享库中集中维护 , 因此在修改目标模块时 , 无需重新链接程序 , 甚至正在运行的程序正在使用现有版本共享库的时候也能够进行这样的变更 。
下面一张图示 , 很形象具体地说明了从创建动态库到链接进可执行文件的过程:
Linux共享库概述文章插图
接下来的另一图示则是很形象具体地说明可创建程序被加载进内存时执行:
Linux共享库概述文章插图
## 使用共享库的有用工具
接下来介绍一些和共享库相关的有用工具
  • lddldd(列出动态依赖)命令显示了一个程序所需的共享库 , 执行如下:
$ ldd xxx1它会以library-name => resolves-to-path的形式将程序所使用的动态库列举出来
  • objdump
该命令可以获取到各类信息 , 具体请参数函数命令手册
  • nm
nm命令会列出目标库或者可执行程序中定义的一组符号 。 这个命令的一个作用是找出哪些库定义了一个符号
共享库的运行为了能够在运行时找到共享库 , 动态链接库遵循了一组标准的搜索规则 , 其中包括搜索一组大多数共享库安装的目录(如:/lib/ //usr/lib 等) , 当然也可以在用户自定义的目录下搜索 , 这一点 , 可以参考相关参考 。
共享库的一些特性动态加载库当一个可执行文件开始运行后 , 动态链接器会加载程序的动态依赖列表中的所有共享库 , 但有些时候 , 延迟加载库是比较有用的 , 如只在需要的时候再加载一个插件 , 动态链接器是通过一组函数来实现的 。 先总体认识下这些函数:
dlopen();dlsym();dlclose();dlerror();打开共享库#include void *dlopen(const char * linfilename,int flag);以上函数通过用户传入的地址目录 , 打开了一个共享库 , 并返回了一个供后续调用使用的句柄 。


推荐阅读