linux下根文件系得统制作工具。内带shell命令
源代码在线查看: unix系统开发-链接处理(1).txt
UNIX系统开发-链接处理(1)
我们已经知道链接实际上是指将在一个模块中引用的符号与它在另一个模块中的定义相链接的过程。并且我们还知道链接分为动态链接和静态链接两种方式。不论是对哪一种方式。链接程序都将搜索程序中的每一个模块,包括所用到的每一个库文件,以在这些文件中寻找在某个模块中没有定义的外部符号的定义。如果没有找到某个被引用的符号的定义,链接程序将报告错误。此时可执行文件的创建将会失败。
对于静态链接和动态链接,其区别主要在于搜索到某个符号的定义后链接程序所做的不同工作:
对静态链接,链接程序将把静态链接库(档案库)中哪些被用户程序所引用的符号定义的目标代码,拷贝到最终生成的可执行文件中。这种情况下,程序中的外部符号引用同其定义的链接是在可执行文件被建立的时候完成的。
对动态链接,共享对象(动态链接库)中的内容在运行时被映射到用户进程的虚地址空间。链接程序所作的仅仅是在最终生成的可执行文件中记录下到哪里去找外部符号定义的目标代码。这种情况下符号的外部引用与其定义的链接是在程序运行时完成的。
在这一节中,我们将详细地讨论链接过程。如编译系统的一些缺省设置、用户如何生成自己的动态库或静态库、如何在程序中链接这些库文件,以及动态链接库是如何实现的,等等问题。在掌握了这些内容之后,读者将能够高效地组织自己的源文件,提高开发的效率和程序的可维护性。
缺省设置
前面一节中,我们使用:
$ cc -o myprg myprog.c myfunc.c
命令来生成可执行文件。此时cc将生成同每一个C源程序对应的目标文件,并把它们彼此链接,以生成一个可执行的程序文件。对于所生成的每一个目标文件,我们称之为可重定位的目标文件,因为这些目标文件中含有尚未同其定义相链接的符号引用,也即尚没有在内存中分配地址。
但我们可以注意到,myprog.c中所调用的printf()和myfunc.c中所调用的isdigit(),这两个函数是我们在自己的程序中所没有定义的。这两个函数是标准C库所提供的。缺省情况下链接程序将自动地道标准C库中去查找哪些被用户程序所调用的函数的定义。
标准的C函数库有动态和静态两个不同的版本,其文件名分别是libc.so和libc.a,分别用于动态链接和静态链接。缺省情况下,链接程序将对标准C库函数调用进行动态链接(使用libc.so),也即所调用的函数将在运行时与程序相链接。但有些标准函数由于设计上的一些遗漏,在libc.so中并没有其定义。对这些函数链接程序将使用libc.a进行静态链接,也即将这些函数的代码拷贝至可执行文件中。但对哪些既可以静态链接,又可以进行动态链接的符号引用,程序员可以自主选择到底使用哪种链接方式。后面我们将介绍如何完成这一点。
标准C函数库中所包含的函数有如下几类:
标准I/O函数,如fopen,fread,fwrite,fclose等;
字符串操作函数,如strcat,strcmp,strcpy等;
对八位字符编码的整数值分类的函数,如isalpha,isupper,islower,isdigit等;
字符、整数或字符串转换函数,如atoi,atol,strtoul,atof等;
用库函数形式实现的系统调用,如open,read,write,close等等。
关于其他未列出的函数及据说明读者可参考有关的手册。
cc自动对标准C库的动态链接是下述约定为基础的:
根据约定,共享对象或动态链接库的名称,前缀是lib而后缀是.so;档案库或者静态链接库,前缀为lib而后缀是.a。因此标准C库的共享版本的名称将是libc.so;而静态版本的名称则是libc.a。
cc命令的-l选项能够识别上述约定。也就是说:
$ cc ... -lx
将使链接程序搜索动态库libx.so或静态库libx.a。缺省情况下,cc将自动地把-lc选项传给链接程序。因此,从实际看-l选项是一个链接程序选项。
缺省情况下,链接程序将优先查找同一目录下的动态库版本libx.so,不成功时才选择静态库libx.a。
缺省情况下,链接程序将在系统的标准位置(/usr/ccs/lib和/usr/lib目录下)按上述顺序搜索所需的库。由编译系统提供的标准库一般被放在/usr/ccs/lib目录下。
在这些约定的基础上,我们可以更明确地讲,缺省的cc命令行将引导链接程序搜索/usr/ccs/lib/libc.so,而不是它所对应的静态库。后面我们将要讲到如何将用户的程序同某个库的静态版本相链接(如同libc.a相链接二不是同libc.so相链接),以及用户如何建立起自己的静态库或动态库,并使程序与这些库相链接。当然,如果缺省的cc命令行能够满足编译要求的话,那么就用不着进行多余的链接处理了。
标准库函数的链接
libc.so只是一个目标文件,其中包含有标准C库中每一个函数的代码。当某个程序调用该库中的某个函数并且动态地将自己的程序相链接时,libc.so的全部内容将被映射到运行时与该程序相对应的进程虚地址空间中。
对于静态库(档案库)则不是这么回事,每一个函数或者一组相关的函数代码被保存到它们自己的目标文件中。然后这些目标文件被收集在一个档案库中。但程序员在命令行中指定对标准C库进行静态链接的时候,链接程序将在档案库中搜索被调用函数的代码并将其拷贝到最终的可执行文件中。这里我们看到使用静态链接时最终可执行文件中只包含有哪些所需的代码。
那么如何使链接程序改变缺省的动态链接方式而进行静态链接呢?方法是在cc命令行中加上-dn选项,如下所示:
$ cc -o myprog -dn myprog.c myfunc.c
这样对于myprog.c和myfunc.c中的标准C库函数调用,链接程序将在libc.a中去搜索目标代码并且将其拷贝到最终可执行的文件中。
在程序比较复杂的情况下,一个程序可能就不是仅仅调用了标准C库中的函数了。例如,对于用到了数学运算sin(),cos()这类函数的程序,它就可能需要同数学函数库链接。由于编译系统只提供了libc和libdl(对动态链接进行控制的函数调用集合)的动态版本,因此,除非是用户自己在标准位置安装了数学函数库的动态版本libm.so,那么链接程序将在标准位置查找libm.a库函数。当然这需要在cc命令行中加上一个-l选项,如下所示:
$ cc file.c file2.c