动态连接和静态连接

做为一名C/C++程序员,对于编译连接的过程要了然于胸。首先大概介绍一下,编译分为3步,首先对源文件进行预处理,这个过程主要是处理一些#号定义的命令或语句(如宏、#include、预编译指令#ifdef等),生成*.i文件;而后进行编译,这个过程主要是进行词法分析、语法分析和语义分析等,生成*.s的汇编文件;最后进行汇编,这个过程比较简单,就是将对应的汇编指令翻译成机器指令,生成可重定位的二进制目标文件。以上就是编译的过程,下面主要介绍两种连接方式--静态连接和动态连接。程序员

        静态连接和动态连接二者最大的区别就在于连接的时机不同,静态连接是在造成可执行程序前,而动态连接的进行则是在程序执行时,下面来详细介绍这两种连接方式。函数

1、静态连接
1.为何要进行静态连接
        在咱们的实际开发中,不可能将全部代码放在一个源文件中,因此会出现多个源文件,并且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另外一个源文件中定义的函数,可是每一个源文件都是独立编译的,即每一个*.c文件会造成一个*.o文件,为了知足前面说的依赖关系,则须要将这些源文件产生的目标文件进行连接,从而造成一个能够执行的程序。这个连接的过程就是静态连接性能

2.静态连接的原理
         由不少目标文件进行连接造成的是静态库,反之静态库也能够简单地当作是一组目标文件的集合,即不少目标文件通过压缩打包后造成的一个文件,以下图,使用ar命令的-a参数查看静态库的组成:.net

 

        这里的*.o目标文件在我前面的博客《从编写源代码到程序在内存中运行的全过程解析》中已经讲的很清楚了,不清楚的能够看一下。翻译

        如下面这个图来简单说明一下从静态连接到可执行文件的过程,根据在源文件中包含的头文件和程序中使用到的库函数,如stdio.h中定义的printf()函数,在libc.a中找到目标文件printf.o(这里暂且不考虑printf()函数的依赖关系),而后将这个目标文件和咱们hello.o这个文件进行连接造成咱们的可执行文件。blog

 

        这里有一个小问题,就是从上面的图中能够看到静态运行库里面的一个目标文件只包含一个函数,如libc.a里面的printf.o只有printf()函数,strlen.o里面只有strlen()函数。内存

        咱们知道,连接器在连接静态连接库的时候是以目标文件为单位的。好比咱们引用了静态库中的printf()函数,那么连接器就会把库中包含printf()函数的那个目标文件连接进来,若是不少函数都放在一个目标文件中,极可能不少没用的函数都被一块儿连接进了输出结果中。因为运行库有成百上千个函数,数量很是庞大,每一个函数独立地放在一个目标文件中能够尽可能减小空间的浪费,那些没有被用到的目标文件就不要连接到最终的输出文件中。开发


3.静态连接的优缺点
        静态连接的缺点很明显,一是浪费空间,由于每一个可执行程序中对全部须要的目标文件都要有一份副本,因此若是多个程序对同一个目标文件都有依赖,如多个程序中都调用了printf()函数,则这多个程序中都含有printf.o,因此同一个目标文件都在内存存在多个副本;另外一方面就是更新比较困难,由于每当库函数的代码修改了,这个时候就须要从新进行编译连接造成可执行程序。可是静态连接的优势就是,在可执行程序中已经具有了全部执行程序所须要的任何东西,在执行的时候运行速度快。博客

问题:io

2、动态连接
1.为何会出现动态连接
        动态连接出现的缘由就是为了解决静态连接中提到的两个问题,一方面是空间浪费,另一方面是更新困难。下面介绍一下如何解决这两个问题。

2.动态连接的原理
        动态连接的基本思想是把程序按照模块拆分红各个相对独立部分,在程序运行时才将它们连接在一块儿造成一个完整的程序,而不是像静态连接同样把全部程序模块都连接成一个单独的可执行文件。下面简单介绍动态连接的过程:

        假设如今有两个程序program1.o和program2.o,这二者共用同一个库lib.o,假设首先运行程序program1,系统首先加载program1.o,当系统发现program1.o中用到了lib.o,即program1.o依赖于lib.o,那么系统接着加载lib.o,若是program1.o和lib.o还依赖于其余目标文件,则依次所有加载到内存中。当program2运行时,一样的加载program2.o,而后发现program2.o依赖于lib.o,可是此时lib.o已经存在于内存中,这个时候就再也不进行从新加载,而是将内存中已经存在的lib.o映射到program2的虚拟地址空间中,从而进行连接(这个连接过程和静态连接相似)造成可执行程序。

3.动态连接的优缺点
        动态连接的优势显而易见,就是即便须要每一个程序都依赖同一个库,可是该库不会像静态连接那样在内存中存在多分,副本,而是这多个程序在执行时共享同一份副本;另外一个优势是,更新也比较方便,更新时只须要替换原来的目标文件,而无需将全部的程序再从新连接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存而且连接起来,程序就完成了升级的目标。可是动态连接也是有缺点的,由于把连接推迟到了程序运行时,因此每次执行程序都须要进行连接,因此性能会有必定损失。

        据估算,动态连接和静态连接相比,性能损失大约在5%如下。通过实践证实,这点性能损失用来换区程序在空间上的节省和程序构建和升级时的灵活性是值得的。

4.动态连接地址是如何重定位的呢?        前面咱们讲过静态连接时地址的重定位,那咱们如今就在想动态连接的地址又是如何重定位的呢?虽然动态连接把连接过程推迟到了程序运行时,可是在造成可执行文件时(注意造成可执行文件和执行程序是两个概念),仍是须要用到动态连接库。好比咱们在造成可执行程序时,发现引用了一个外部的函数,此时会检查动态连接库,发现这个函数名是一个动态连接符号,此时可执行程序就不对这个符号进行重定位,而把这个过程留到装载时再进行。————————————————版权声明:本文为CSDN博主「kang___xi」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。原文连接:https://blog.csdn.net/kang___xi/article/details/80210717

相关文章
相关标签/搜索