静态链接和动态链接

来源:互联网 发布:网络正常微信发不出去 编辑:程序博客网 时间:2024/05/19 19:57

引言

即使是最简单的HelloWorld的程序,它也要依赖于别人已经写好的成熟的软件库,这就是引出了一个问题,我们写的代码怎么和别人写的库集成在一起,也就是链接所要解决的问题。

首先看HelloWorld这个例子:
// main.c  1 #include <stdio.h>  2  3 int main(int argc, char** argv)  4 {  5         printf("Hello World! argc=%d\n", argc);  6         return 0;  7 }

HelloWorld的main函数中引用了标准库提供的printf函数。链接所要解决的问题就是要让我们的程序能正确地找到printf这个函数。
解决这个问题有两个办法:一种方式是在生成可执行文件的时候,把printf函数相关的二进制指令和数据包含在最终的可执行文件中,这就是静态链接;另外一种方式是在程序运行的时候,再去加载printf函数相关的二进制指令和数据,这就是动态链接。
每个源文件都会首先被编译成目标文件,每个目标文件都提供一些别的目标文件需要的函数或者数据,同时又从别的目标文件中获得一些函数或者数据。因此,链接的过程就是目标文件间互通有无的过程。

静态链接

静态链接就是在生成可执行文件的时候,把所有需要的函数的二进制代码都包含到可执行文件中去。因此,链接器需要知道参与链接的目标文件需要哪些函数,同时也要知道每个目标文件都能提供什么函数,这样链接器才能知道是不是每个目标文件所需要的函数都能正确地链接。如果某个目标文件需要的函数在参与链接的目标文件中都找不到的话,链接器就报错了。

动态链接

静态链接看起来很简单,但是有些不足。其中之一就对磁盘空间和内存空间的浪费。标准库中那些函数会被放到每个静态链接的可执行文件中,在运行的时候,这些重复的内容也会被不同的可执行文件加载到内存中去。同时,如果静态库有更新的话,所有可执行文件都得重新链接才能用上新的静态库。动态链接就是为了解决这个问题而出现的。所谓动态链接就是在运行的时候再去链接。理解动态链接需要从两个角度来看,一是从动态库的角度,二是从使用动态库的可执行文件的角度。

从动态库的角度来看,动态库像普通的可执行文件一样,有其代码段和数据段。为了使得动态库在内存中只有一份,需要做到不管动态库装载到什么位置,都不需要修改动态库中代码段的内容,从而实现动态库中代码段的共享。而数据段中的内容需要做到进程间的隔离,因此必须是私有的,也就是每个进程都有一份。因此,动态库的做法是把代码段中变化的部分放到数据段中去,这样代码段中剩下的就是不变的内容,就可以装载到虚拟内存的任何位置。那代码段中变化的内容是什么,主要包括了对外部函数和变量的引用。

小结

链接解决我们写的程序是如何和别的库组合在一起这个问题。每个参与链接的目标文件中都提供了这样的信息:我有什么符号(变量或者函数),我需要什么符号,这样链接器才能确定参与链接的目标文件和库是否能组合在一起。静态链接是在生成可执行文件的时候把需要的所有内容都包含在了可执行文件中,这导致的问题是可执行文件大,浪费磁盘和内存空间以及静态库升级的问题。动态链接是在程序运行的时候完成链接的,首先是动态链接器被加载到内存中,然后动态链接器再完成类似于静态链接器的所做的事情。
0 0