静态库和动态库


=Start=

缘由:

补充系统知识

正文:

参考解答:

我们通常把一些公用函数制作成函数库,供其它程序使用(代码的复用)。函数库可分为静态库和动态库两种:

  • 静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库;
  • 动态库在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入,因此在程序运行时还需要动态库存在。

动态库和静态库二者的不同点在于代码被载入的时刻不同。

静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。

静态情况下,把库直接加载到程序中,而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

1.什么是库?

在Windows平台和Linux平台下都大量存在着库。从本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于Windows和Linux的本质不同,因此二者库的二进制是不兼容的。本文仅限于介绍Linux下的库。

2.库的种类

Linux下的库有两种:静态库和动态库(共享库)。二者的不同点在于代码被载入的时刻不同。

  • 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
  • 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
3.库存在的意义

库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。

现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

4.在Linux下如何生成库文件?

Linux下静态库的后缀是.a,它的产生分两步:

Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表;

Step 2.用ar命令将很多.o转换成.a,成为静态库;

Linux下动态库的后缀是.so,它由gcc加特定参数编译产生。

例如:
$ gcc -fPIC -c *.c

$ gcc -shared -Wl,-soname, libfoo.so.1 -olibfoo.so.1.0 *.

5.库文件是如何命名的,有没有什么规范?

在Linux下,库文件一般放在/usr/lib和/lib下(64位系统对应的是/usr/lib64和/lib64):

  • 静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称;
  • 动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号。
6.如何知道一个可执行程序依赖哪些库

ldd命令可以查看一个可执行程序依赖的共享库,例如:

# ldd /bin/ln

libc.so.6 => /lib/libc.so.6 (0×40021000)

ld-linux.so.2 => /lib/ld-linux.so.2 (0×40000000)

可以看到ln命令依赖于libc库和ld-linux库。

7.可执行程序在执行的时候如何定位共享库文件?

当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。

此时就需要系统动态载入器(dynamiclinker/loader),对于elf格式的可执行程序,是由ld-linux.so*来完成的。

它先后搜索elf文件的DT_RPATH段,环境变量LD_LIBRARY_PATH,/etc/ld.so.cache文件列表,/lib/,/usr/lib目录,找到库文件后将其载入内存。

  1. (仅ELF文件)使用可执行文件中DT_RPATH区域设置的属性,如果DT_RUNPATH被设置,那么忽略DT_RPATH(在我的Linux对应的是RPATH和RUNPATH);
  2. 使用环境变量LD_LIBRARY_PATH,如果可执行文件中有 set-user-id/set-group-id 会被忽略;
  3. (仅ELF文件)使用可执行文件中DT_RUNPATH区域设置的属性;
  4. 从/etc/ld.so.cache缓存文件中查找;
  5. 从默认路径/lib、/usr/lib文件目录中查找。
8.在新安装一个库之后如何让系统能够找到它?

如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。

如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

1.编辑/etc/ld.so.conf文件,加入库文件所在目录的路径。

2.运行ldconfig,该命令会重建/etc/ld.so.cache文件。

参考链接:

=END=

, ,

《 “静态库和动态库” 》 有 7 条评论

  1. Linux下同时连接动态库和静态库
    http://github.tiankonguse.com/blog/2017/05/14/lib-static-dynamic.html
    `
    Linux下链接库时使用-L来指定路径,使用-l来指定库名。默认情况下优先找动态库,找不到了再找静态库。
    如果直接使用-static或者-dynamic会使所有库都使用这种形式链接,显示不是我们想要的。

    当我们想要为某些库链接静态库,某些链接静态库,其余的按默认链接,则需要下面的样子:
    -L./lib/test/ -Wl,-Bstatic -ltest #指定静态库
    -L./lib/test/ -Wl,-Bdynamic -ltest #指定动态库
    -Wl,-Bdynamic #恢复默认设置
    `

  2. 一文弄懂Java和C中动态链接机制
    https://juejin.im/post/5c5266926fb9a049b41ce30b
    `
    概念
     模块、符号和链接
     静态链接和动态链接
    语言层面的对比
     编译期的C/C++
      静态链接库和共享库
     编译期的Java
     编译期对比
     运行期的C/C++
     运行期的Java
     动态加载
    动态链接的对比
    总结
    Ref
    `

  3. 知名压缩软件 xz 被发现有后门,影响有多大?如何应对?
    https://www.zhihu.com/question/650826484/answer/3448806357
    `
    大意是一个做测试的老哥因为服务器的风扇很吵,然后去检查发现sshd服务占用了大量的CPU资源(CPU发热多嘛),然后他发现在liblzma(就是xz的部分)占用了大量的CPU,然后他就想去查查到底哪部分代码跑的那么慢,结果调试时发现,这部分居然没有对应符号表。

    啥是符号表呢,简单来说源代码到编译成程序时,会将源码和二进制程序做个对应,当程序出问题时,就能方便你查找到对应源码,因为这个恶意后门代码本身就是以二进制程序的方式插入进来的,没有经过这个源码到程序的编译过程,自然就没有符号表咯,那这个插入的部分,到底在隐藏什么?

    测试老哥越想越不对劲,于是就有了上面这个邮件,可以说要不是这老哥的敬业水平和技术水平之高如此可见一斑,换其它任何一个草台班子,这个鸡脚都不会漏出来。
    `

发表回复

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