Linux动态链接

作者: linjinhe | 来源:发表于2017-04-29 14:26 被阅读457次

问题

曾经不止一次遇到过这样的情况:从机器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是一个动态链接库的绝对路径。

相关文章

  • 操作系统

    • Linux静态链接和动态链接; (转)静态链接和动态链接1、静态链接静态链接方法:#pragma comme...

  • Linux动态链接

    问题 曾经不止一次遇到过这样的情况:从机器A拷贝一个二进制文件到另一台机器B,两台机器的操作系统版本一样,可是在机...

  • iOS代码层获取电量

    1.加载动态链接库 iOS是给予Linux内核,在Linux调用如下函数来加载动态链接库:dlopen,dlsym...

  • Linux[链接]: 静态链接,动态链接及linux内存布局

    Linux[链接]: 静态链接,动态链接及linux内存布局 一. 目标文件 1.1 目标文件概述 现在PC平台流...

  • 20_链接过程简介

    关键词:静态链接、Linux下静态库的创建和使用、动态链接、 Linux下动态库的创建和使用 1. 问题 工程中的...

  • Android ELF文件got表符号偏移的确定

    众所周知Android的动态链接器是linker,iOS是dyld,linux是ld-linux.so.2。由于同...

  • note_4.1_Linux目录结构与根文件系统

    Linux文件系统 Linux:glibc程序编译方式: 动态链接 静态编译 进程的类型:终端:硬件设备,关联一个...

  • 【Linux入门第9天】Linux根文件系统层级标准FHS

    linux:glibc 程序编译方式: 动态链接 静态链接 进程的类型: 终端: 硬件设备,关联一个用户接口 与终...

  • _dl_runtime_resolve

    简介 在Linux中如果程序想要调用其它动态链接库的函数,必须要在程序加载的时候动态链接;在一个程序运行过程中,可...

  • Linux下C++开发动态库so及调用方式

    对于公共功能,需要将其封在在一个公共库中供其他模块调用,动态链接库是常有的一种方式,在Linux下的C++动态链接...

网友评论

    本文标题:Linux动态链接

    本文链接:https://www.haomeiwen.com/subject/kccszttx.html