热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux下的动态共享链接库的分析与使用

文章标题:Linux下的动态共享链接库的分析与使用。Linux是中国IT实验室的一个技术频道。包含桌面应用,Linux系统管理,内核研究,嵌入式系统和开源等一些基本分类

  动态共享库的工作方式与静态链接库不同。对于每个使用静态链接库的应用程序而言,在应用程序中都存在着静态链接库拷贝。但是动态共享库却不是这样的,动态共享库是被所有使用它的应用程序共享的,无论调用一个动态共享库的进程有多少,系统中始终只运行着一个动态共享库,这里动态共享库中“共享”的含义。至于“动态”,则主要强调的是链接发生在什么阶段。对于静态链接库而言,链接过程发生在编译阶段,操作系统在加载程序时不再对程序做任何改变,因此“静态”链接;然而对于使用动态共享库的程序而言,编译器在编译程序时只知道程序

  将要使用到某个动态共享库中的某个符号。至于这个符号所对应的具体实体,在编译时则是未知的。从符号转换为实体的工作留给了操作系统在加载程序时支完成。这样一个转换过程实质上就是把程序的链接过程推迟到了程序执行时来完成。这与在编译期间完成链接雷管显然是不一样的。这也是动态共享库被冠以“动态”的原因。

  动态共享库有以下的优点,使它在Linux开发中比静态链接库更加的流行。

  (1) 节省内存

  动态共享库无论被多少应用程序使用,在内存中都只存在一个动态共享库的副本,而不像静态链接库那样,一个应用程序在运行中用到静态链

  接库,就会有多个静态链接库的副本 。

  (2) 节省磁盘

  这和节省内存有点相似,同样这也是由于静态链接库存在多个静态链接库的副本造成的。同样的应用程序,使用动态共享库编译出的版本通常比使用静态链接库编译出来的版本要小。因此,在嵌入式系统开发中使用动态共享库也不节省空间,提供了一种很好的选择。

  (3) 便于软件修复与升级

  由于动态共享是独立于应用程序存在的,因此,用新版本的动态共享库替旧版本的工作将变得非常容易。如果使用静态链接库的话,假设在一个静态库中发现了一个bug,那么要修正这个bug的话,就要重新编译所有使用这个静态库的应用程序,使用这个静态库的应用程序有很多的话,可以想像工作量是有多大。

  (4) 提高性能

  与采用静态链接库臃肿的应用程序相比,采用动态共享库的应用程序明显“苗条”得多,这样当操作系统加载应用程序时,是需要把应用程序

  复制到内存中的,这样的“苗条”的动态链接库也就有了很大的优势,同时提高了程序的性能。

  当然,动态链接库在有上述这些优势的同时,也有以下的几个劣势。复杂性,兼容性,调试困难。但是它在Linux上使用频率上仍然比静态链接库要高的多。应用的更加广泛。

  动态共享库的重要概念-----soname

  动态共享库有一个重要的概念---soname。动态共享库在Linux系统上是以文件的形式存在的,这样,每个动态共享库也就有一个文件名,假设把动态共享库的文件名定义为filename。那么必须牢记一件事性就是soname和filename不是一个概念的。在Linux下,每个动态共享库都必须被赋予一个按特定的名称,Linux的文档将其称之为soname。soname通常包含共享库的名字和版本号,通过soname,系统或链接器可以唯一地确定一个动态共享库。比如Linux的C函数库的soname是libc.so.6,这里,c是函数库的名字,6是该动态共享库的版本号。

  然而,应用程序并不是直接和名字为soname的文件相链接的。比如,对于Linux C库而言,尽管通常在系统中能够找到名为libc.so.6的文件,但这个文件实际上却只是一个软连接也就是符号链接。这里清楚地显示出libc.so.6是一个到libc-2.3.2.so的软连接。那么,这个软连接是由ldconfig建立的。ldconfig做的事情就是配置动态链接器的运行时绑定。对于一个编译好的动态链接库,如何知道它的soname是什么呢?可以使用readelf。readelf有一个选项-d,这个选项可以打印出ELF文件中dynameic段的内容。在ELF中的dynamic段中就包含着动态共享库的soname。在Linux系统中存在着一个文件 /etc/ld.so.conf。这个文件中的每一行指定了ldconfig应当搜索的目录,在这些目录下面存放着系统运行中所需要的动态共享库文件,以.so.x.x结尾的文件;ldconfig依次搜索这些目录,为找到的每个动态共享库文件建立一个到共soname的软链接。

  动态共享库的构建和安装

  在为动态共享库编译目标文件时,GCC编译器的下面这些选项是需要的:

  -share:这个选项告诉GCC生成共享目标文件。生成的共享目标文件可以与其他目标文件链接在一起构成一个可自执行文件,此选项必须和-fPIC等选项联合使用。

  -fPIC:这个选项告诉GCC生成位置无关代码(Position-Independent Code,PIC)在共享库中应当使用位置无关代码.

  -Wl,-soname,xxx:这是一个特殊的GCC选项。通过该选项,GCC会把-soname,xxx作为一个命令行选项传递给链接器ld,ld拿这个选项来做什么呢?在每个动态共享库的dynamic段都有一个soname项。-soname,xxx选项的作用就是告诉链接器ld,将要链接产生的文件是一个动态共享库,它的soname是xxx.比如,如果编译版本号为6的Linux C库,就应当在生成libc-2.3.2.so时给GCC指定链接选项-Wl,-soname,libc.so.6.

  构建动态共享库的最后一个步骤通常是下面的一个命令行:

  gcc -share -Wl,soname,xxx -o libname filelist liblist

  在这个命令行中,libname表示最终产生的动态共享库文件名。比如libc-2.3.2.so.filelist是一组目标文件列表,它表明了哪些编译好的目标文件将放到最终产生的动态共享库里面去。由于动态共享库可以依赖于其他共享库,因此这一项指定了最终产生的动态共享库将依赖的那些共享库的列表。

  动态共享库在构建完成之后,如果需要安装到特定和系统目录下(如最常见的/usr/local/lib目录),只需要将动态共享库文件复制到相应的目录下即可。然后运行ldconfig建立以soname命名的软连接,前提是共享库所在的目录包含在/etc/ld.so.conf文件中,此外 ,为了让链接器能够以标准的方式与动态共享库链接,还需要创建一个不带版本号的软连接。我们可以看到在Linxu系统下的lib目录下有很多的的.so.XX 的文件,这就是系统中使用到的动态共享库

  其中我们可以看到libc.so.6.这个是linux下的C函数库文件。我们可以看到这是一个符号链接,真正的文件是libc-2.10.2.so.

  #lib$ ls -l libc.so.6

  lrwxrwxrwx 1 root root 14 2009-12-09 20:59 libc.so.6 -> libc-2.10.1.so

  #lib$ readelf -d libc-2.10.1.so

  Dynamic section at offset 0x168b40 contains 26 entries:

  Tag Type Name/Value

  0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]

  0x000000000000000e (SONAME) Library soname: [libc.so.6]

  0x000000000000000c (INIT) 0x1e7b0

  0x000000000000001a (FINI_ARRAY) 0x365740

  0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)

  0x0000000000000004 (HASH) 0x1620d8

  0x000000006ffffef5 (GNU_HASH) 0x2b8

  0x0000000000000005 (STRTAB) 0x10560

  0x0000000000000006 (SYMTAB) 0x3c00

  0x000000000000000a (STRSZ) 21963 (bytes)

  0x000000000000000b (SYMENT) 24 (bytes)

  0x0000000000000003 (PLTGOT) 0x368fe8

  0x0000000000000002 (PLTRELSZ) 192 (bytes)

  0x0000000000000014 (PLTREL) RELA

  0x0000000000000017 (JMPREL) 0x1e5d8

  0x0000000000000007 (RELA) 0x16e38

  0x0000000000000008 (RELASZ) 30624 (bytes)

  0x0000000000000009 (RELAENT) 24 (bytes)

  0x000000006ffffffc (VERDEF) 0x16bf8

  0x000000006ffffffd (VERDEFNUM) 15

  0x000000000000001e (FLAGS) STATIC_TLS

  0x000000006ffffffe (VERNEED) 0x16e08

  0x000000006fffffff (VERNEEDNUM) 1

  0x000000006ffffff0 (VERSYM) 0x15b2c

  0x000000006ffffff9 (RELACOUNT) 1190

  0x0000000000000000 (NULL) 0x0

  下面以foo.c和bar.c 文件为例:如何构建动态共享库

  #:~/program$ gcc -fPIC -g -c -o foo.o foo.c

  #~/program$ gcc -fPIC -g -c -o bar.o bar.c

  #:~/program$ gcc -shared -g -Wl,-soname,libfoobar.so.0 -o libfoobar.so.0.0 foo.o bar.o -lc

  #:~/program$ sudo cp libfoobar.so.0.0 /usr/local/lib

  #:~/program$ sudo ldconfig

  #:~/program$ cd /usr/local/lib

  #:/usr/local/lib$ ls

  libfoobar.so.0 libfoobar.so.0.0 python2.6

  #:/usr/local/lib$ ln -sf libfoobar.so.0 libfoobar.so

  ln: creating symbolic link `libfoobar.so': Permission denied

  #:/usr/local/lib$ sudo ln -sf libfoobar.so.0 libfoobar.so

  #:/usr/local/lib$

  #:~/program$ gcc -g -o foobar main.c -lfoobar

  #:~/program$ ./foobar

  This is foo!library2 is

  foo()=foo

  This is library1 is called

  bar()=bar

  这里的共享库的soname指定为libfoobar.so.0,最终生成的动态共享库文件为libfoobar.so.0.0,foo.o和bar.o是要放到libfoobar.so.0-.0中的目标文件列表,-lc则是libfoobar.so.0.0所依赖的共享库列表,这里只有一个Linux C库被依赖。接着把libfoobar.so.0.0安装到/usr/local/lib目录上去,然后运行ldconfig,同时为了让链接器能够链接上libfoobar.so.0.0,还要创建一个指向libfoorbar.so.0和符号连接。

  这里简要的分析了一下Linux动态共享库的使用,为以后自己的使用做个记录。


推荐阅读
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Python字典推导式及循环列表生成字典方法
    本文介绍了Python中使用字典推导式和循环列表生成字典的方法,包括通过循环列表生成相应的字典,并给出了执行结果。详细讲解了代码实现过程。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • 本文介绍了Python版Protobuf的安装和使用方法,包括版本选择、编译配置、示例代码等内容。通过学习本教程,您将了解如何在Python中使用Protobuf进行数据序列化和反序列化操作,以及相关的注意事项和技巧。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
author-avatar
虚伪小仔
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有