Linux动态链接

问题

曾经不止一次遇到过这样的情况:从机器A拷贝一个二进制文件到另一台机器B,两台机器的操作系统版本一样,可是在机器A能正常运行,在机器B却提示错误。最常见的就是提示动态链接库找不到,如:

./test: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory

其实就是说,找不到动态链接库libstdc++.so.6

最近又有一次碰到类似的问题,所以顺便把动态链接库的基本原理了解了一遍。

静态链接

静态链接库,在Linux下文件名后缀为.a,如libstdc++.a。在编译链接时直接将目标代码加入可执行程序。

动态链接

动态链接库,在Linux下是.so文件,在编译链接时只需要记录需要链接的号,运行程序时才会进行真正的“链接”,所以称为“动态链接”。如果同一台机器上有多个服务使用同一个动态链接库,则只需要加载一份到内存中共享。因此,动态链接库也称共享库

命名规则

动态链接库与应用程序之间的真正链接是在应用程序运行时,因此很容易出现开发环境和运行环境的动态链接库不兼容或缺失的情况。

Linux通过规定动态链接库的版本命名规则来管理兼容性问题。

Linux规定动态链接库的文件名规则比如如下:

libname.so.x.y.z

  • lib:统一前缀。
  • so:统一后缀。
  • name:库名,如libstdc++.so.6.0.21的name就是stdc++。
  • x主版本号。表示库有重大升级,不同主版本号的库之间是不兼容的。如libstdc++.so.6.0.21的主版本号是6。
  • y次版本号。表示库的增量升级,如增加一些新的接口。在主版本号相同的情况下,高的次版本号向后兼容低的次版本号。如libstdc++.so.6.0.21的次版本号是0。
  • z发布版本号。表示库的优化、bugfix等。相同的主次版本号,不同的发布版本号的库之间完全兼容。如libstdc++.so.6.0.21的发布版本号是21。

另外,Linux下的一个动态链接库会有下面三个名字:

libstdc++.so -> libstdc++.so.6.0.21*
libstdc++.so.6 -> libstdc++.so.6.0.21*
libstdc++.so.6.0.21*
  • libstdc++.so:linker name,程序编译链接时如果依赖了共享库,链接器只认不带任何版本的共享库。如果存在多个同名(上面命名规则中的name)动态链接库,linker name会指向最新的一个。
  • libstdc++.so.6:SO_NAME, 程序运行时会按照这个名称去找真正的库文件。也就是说,ELF可执行文件中保存的动态库名就是SO_NAME。如果存在多个同一主版本号的动态链接库,SO_NAME会指向最新的一个。
  • libstdc++.so.6.0.21:real name,这是动态链接库的真正名称。

相关路径

  • /lib:最关键和基础的动态链接库。
  • /usr/lib:关键的动态链接库。
  • /usr/local/lib:第三方动态链接库。
  • 由/etc/ld.so.conf配置文件指定的目录。

ldconfig

动态链接器不可能在每次查找动态链接库都去遍历所有动态链接库的目录,这样速度太慢了。因此,在系统启动时会通过ldconfig为动态链接库生成SO_NAME/etc/ld.so.cache存放系统动态链接库的路径信息,加速动态链接库的查找。

程序启动查找动态链接库的路径顺序如下:

  1. LD_LIBRARY_PATH指定的路径。
  2. 由路径缓存文件/etc/ld.so.cache指定的路径。
  3. 默认共享库目录,先/usr/lib,然后/lib

注意,安装动态链接库后,需要重启系统或运行ldconfig生成SO_NAME和刷新/etc/ld.so.cache文件。

ldd

通过ldd elf_file可以查看ELF文件依赖哪些动态链接库,如

$ ldd test
linux-vdso.so.1 =>  (0x00007ffc89b46000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6e20ec7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f6e20bc1000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6e209ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6e205e3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6e211cb000)
  • linux-vdso.so.1是内核提供的一个动态链接库,所以这里只有一个内存地址。
  • /lib64/ld-linux-x86-64.so.2是一个动态链接库的绝对路径。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程坑太多

eclipse 集成阿里的p3c插件

35830
来自专栏魏艾斯博客www.vpsss.net

去掉 WordPress 网页图片默认链接功能

18330
来自专栏IT民工生存指南

从0开始Vue.js 和 Webpack 4 [1]

19650
来自专栏无原型不设计

【Mockplus教程】复制/克隆

复制是将页面复制到内存中,克隆是直接创建一个和原页面内容一样的新页面。 1. 复制 选中需要复制的页面,鼠标右键单击,弹出的菜单中选择“复制”, 然后在...

32030
来自专栏地方网络工作室的专栏

Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(四)调整 App.vue 和 router 路由

Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(四)调整 App.vue 和 router 路由 前情回顾 在上一篇《V...

24590
来自专栏从零开始学自动化测试

Selenium2+python自动化69-PhantomJS使用

前言 PhantomJS是一个没有界面的浏览器,本质上是它其实也就是一个浏览器,只是不在界面上展示。 PhantomJS非常适合爬虫方面,很多玩爬虫的都喜欢用这...

30440
来自专栏吴伟祥

防止用户将表单重复提交的方法 原

表单重复提交是在多用户Web应用中最常见、带来很多麻烦的一个问题。有很多的应用场景都会遇到重复提交问题,比如:

12120
来自专栏公众号_薛勤的博客

Maven报错Archive for required library:某.jar' in project '项目名'

8710
来自专栏一“技”之长

AppleWatch开发入门三——代码交互与控制器生命周期

        在前两篇博客中,讨论了关于watch开发中框架与界面布局相关,然而主要的逻辑,终究还是要通过代码来实现的,在我们创建了项目之后,就会生成Inte...

8930
来自专栏DT乱“码”

微信小程序开发指引

官方文档教程1:http://bcoder.cn/wxopen/ 官方文档教程2:http://bing.aliaii.com/wxopen/  本文档将带你一...

571100

扫码关注云+社区

领取腾讯云代金券