动态共享库的工作方式与静态链接库不同。对于每个使用静态链接库的应用程序而言,在应用程序中都存在着静态链接库拷贝。但是动态共享库却不是这样的,动态共享库是被所有使用它的应用程序共享的,无论调用一个动态共享库的进程有多少,系统中始终只运行着一个动态共享库,这里动态共享库中“共享”的含义。至于“动态”,则主要强调的是链接发生在什么阶段。对于静态链接库而言,链接过程发生在编译阶段,操作系统在加载程序时不再对程序做任何改变,因此“静态”链接;然而对于使用动态共享库的程序而言,编译器在编译程序时只知道程序
将要使用到某个动态共享库中的某个符号。至于这个符号所对应的具体实体,在编译时则是未知的。从符号转换为实体的工作留给了操作系统在加载程序时支完成。这样一个转换过程实质上就是把程序的链接过程推迟到了程序执行时来完成。这与在编译期间完成链接雷管显然是不一样的。这也是动态共享库被冠以“动态”的原因。
动态共享库有以下的优点,使它在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动态共享库的使用,为以后自己的使用做个记录。
阅读(2358) | 评论(0) | 转发(1) |