编译的学习和实践日志六[链接和库]

 钟鼓馔玉不足贵,但愿长睡不复醒! from 《觉主语录》
最近这两天总是起的很晚,大概都到12点了吧。也许是熬夜太多,可是在学校这种环境下,也只有晚上才能让我静下心来学习吧。
今天是稍硬的话题,库和链接方面的内容。库分为动态库和静态库,在linux下的后缀名分别为.so/.a 在win下应该是.dll/.lib。动态和静态的主要区别在于库的内容装入可执行文件的方式:静态库是在程序链接的时候直接把数据复制到可执行文件中去,而动态库则是在程序运行的时候再链接到可执行文件。这个和以前学习操作系统的时候讲的程序链接的方式是一致的,有学过的同学可以回忆下。下面总结几条主要区别:
1、生成格式不同,静态库是以文件为单位生成的,而动态库是函数/变量为单位。静态库生成的时候把每个源文件的信息都复制过来,然后再把文件包装下,而动态库则是把所有文件的函数/变量一视同仁,一起打包。
2、对库里函数名字的要求不同,静态库可以在不同的源文件下有题相同名字的函数,而动态库绝对不可以。例如静态库libtest.a里面有两个源文件a.c和b.c,里面可以都有一个test()的函数,当然链接使用的话,谁靠前使用谁,而动态库内部则没有源文件的概念,所有的函数都在一起,所以不能有两个test()。
3、链接后的信息冗余度不同,静态库在链接的时候会把某个函数所在源文件的所有代码都复制到可执行文件中去,例如libtest.a里面有testa1()(属于a.c),testa2()(属于a.c),testb1()(属于b.c)三个独立无关的函数,如果链接文件用到了testa1()则同在a.c下的testa1()和testa2()都必须复制到目标文件中去,但testb1()不用复制。如果是动态库则只会复制testa1(),这也说明了静态库的本质是文件为单位的。
4、链接的次序要求不同,如果一个静态库liba.a依赖于另外一个静态库libb.a那么在链接的时候libb.a一定要写到liba.a前面,否则就出现依赖错误。而动态库则对顺序没有要求。
5、装入时间不同,如上所说静态是连接时装入,而动态是执行时装入。链接时装入的话每个用到该库的文件必须都得复制一份代码,也增加了冗余,而且库文件升级的话,目标文件不会随着升级。但所有的动态链接库在系统中进保存一份就可以了。每个程序调用它的时候都是通过虚拟内存映射过去,不用为每个程序都运行一次动态库。而且升级的时候只要动态库生了,所有使用该库的程序不用做任何设置也跟着升级了,省去了重新链接的麻烦(不过要确保主版本的兼容性)。
6、代码共享度不同,如上条说的,可以看出来所有程序共用一份代码和每个程序各执一份代码哪个共享度更高。
7、对符号表的依赖度不同,如果将strip作用于静态库,去掉其中的符号表,那么静态库就会失效,而动态库还另外保存一份动态符号表,所以去掉之后还是可以正常运行的,只是某些信息看不到了。
以上是总结,今天晚上还遇到两个比较奇怪的事情:
1、我在链接文件的时候使用这个命令ld 1.o -L. -lfg –dynamic-linker /lib/ld-linux.so.2这样会链接当前目录的libfg.so和/lib/ld-linux.so.2,但是它只链接了libfg.so和linux-gate.so并没有链接ld-linux.so.2。gdb调试提示找不到ld-linux.so.2,当我把–dynamic-linker/lib/ld-linux.so.2去掉用默认的动态链接选项时也能链接通过,但是调试和ldd都提示无法找到/usr/lib/libc.so.1,当我从/lib下找到这个文件link过去再查看,它又提示段错误,真是很晕。最后我上网看了下,有人这样写了一个命令ld
1.o -L. -lfg –dynamic-linker/lib/ld-linux.so.2 -lc多了个要求链接libc.so。这样居然把libc和ld-linux都链接进去了。真不晓得是什么原因造成的这个样子,那位大大可以给解释下么?
2、使用gdb调试我上面链接好的文件,断点正常生效,但是用insight内建的控制台gdb调试断点居然不能用,直接就运行完毕了。不晓得怎么回事,下面附上a.out 和libfg.so 调试的时候两个文件放到同一目录下即可。

ps:虽然自己的钱包各种证件在上个周日丢了,但是这两天心情却出奇的好…

davelv
2009-11-04

This entry was posted in 程序设计, 编译与语言 and tagged , . Bookmark the permalink.

发表回复

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