C语言——链接的思考

来源:互联网 发布:网络电视怎么放直播 编辑:程序博客网 时间:2024/06/13 22:51

对于链接的思考

                  静态链接       750Kb              506Kb              ________________> libc.a         产生:a.out               1Kb        /hello.o ----|                                \________________> libc.so------->产生:a.out                          动态链接       620Kb               5Kb                                              库函数在运行时被映射到进程中

即使在静态链接中,整个libc.a文件并没有全部装入可执行文件中,所装入的只是所需要的函数!

动态链接的优点

  • 动态链接相比静态链接可执行文件体积小。能节省磁盘空间和虚拟内存,因为函数库只有在需要的时候才被映射到进程。

  • 所有动态链接到某特定函数库的可执行文件在运行时共享该函数库的一个单独拷贝。系统内核保证映射到内存的函数库
    可被所有使用它的进程共享.如果是静态链接将会有多份拷贝映射到内存,使消耗更多物理内存,引起更多换页。

    系统调用mmap()把文件映射到进程的地址空间。这样,文件的内容可以通过读取连续的内存地址来获得。

  • 动态链接函数库版本升级方便,新函数库随时发布,只要安装到系统中,旧程序就可自动获得新函数库优点而不用重新链接

    使用共享函数库的主要原因是获得ABI(应用程序二进制接口)的好处–软件不必因新版本函数库或操作系统的发布而重新链接

  • 动态链接库允许用户在运行时选择需要执行的函数库,根据自己的需求在程序执行时用一个库代替另一个库文件。

    任何人都可以创建静态或动态函数库。只需简单编译一些不含main()的代码,并把编译生成的.o文件用正确的工具处理
    ————静态库使用”ar“(.a扩展名,archive)
    ————动态库使用”ld“(.so扩展名,shared libraries)

动态链接库可以用-G来创建:

cc -o libfruit.so -G tomato.c

然后利用这个库编写程序,并且使用以下方法链接:

cc test.c -L/home/linden -R/home/lindeb -lfruit //是字母’l‘,不是数字’1‘

-L和-R是分别告诉链接器在”链接“时和”运行“时需要从哪个目录寻找链接的函数库

位置无关代码

编译器选项-K pic可以产生位置无关代码

* 与位置无关的代码表示这种用法产生的代码保证对于任何全局数据的访问都是通过额外的间接方法完成的。这使它更容易对数据
进行重定位,只要简单修改全局偏移量表中的一个值就可以了。类似的每个函数调用的产生就像通过过程链接表的某个间接地址所
产生的一样。这样文本可以很容易的重新定位到任何地方,只要修改下偏移量表就可以了。所以当代码在运行时被映射进来时,运
行时链接器可以直接把他们放在任何空闲的地方,而代码本身不用修改。
详见GOT&PLT.md
* 在缺省情况下编译器不会产生位置无关代码,因为额外的指针解除引用操作会使程序稍稍变慢。但是如果不使用位置无关的代码,
所产生的代码就会被对应到固定固定的位置,这对可执行文件来说是很好,但对于共享库速度却慢些,因为现在每个全局引用旧不
得不在运行时通过修改页面安排到固定位置,使得页面无法共享。
* 运行时链接器总能安排对页面的引用。但是使用位置无关代码,任务被极大简化了。
根据经验,对于函数库应该始终使用位置无关代码。对于共享库,位置无关代码显得格外有用,因为每个使用共享库的进程一般都
会把它映射到不同的虚拟地址(尽管是共享同一份物理拷贝)

函数链接库的5个”特殊秘密“


  1. 动态库文件扩展名是”.so“,静态库是”.a“

动态库与共享库的区别:

动态加载库(dynamicallyloaded (DL) libraries)是指在程序运行过程中可以加载的函数库。而不是像共享库一样在程序启动
的时候加载。DL对于实现插件和模块非常有用,因为他们可以让程序在允许时等待插件的加载。在Linux中动态库跟共享库的格式没
有区别,主要区别在于共享库是运行时加载,有专门一组API用于完成打开动态库、查找符号、处理出错、关闭动态库等功能。

  • 例如,可以通过-lthread选项,告诉编译器链接到libthread.so
  • 编译器期望在确定的目录找到库,

    -Lpathname和-Rpathname
  • 观察头文件,确认所使用的函数库

  • 0 0