您的位置:首页 > 其它

动态链接和静态链接

2017-02-18 15:05 239 查看

什么是库

库从本质上来说是一种可执行的二进制文件,可以被加载到内存中运行,而根据链接时期的不同,库又可以分为静态库和动态库。

链接

链接就是将不同部分的代码和数据收集和组合成一个单一文件的过程,也就是把不同目标文件合并成最终可执行文件的过程,注意:这个过程不涉及内存,链接按时期的不同可以分为三种形式,分别是:

1. 编译时链接:这个其实就是我们常说的静态链接过程;

2. 装载时链接;

3. 运行时链接;

其中,装载时链接和运行时链接被称为动态链接;

什么是静态链接

静态链接就是在编译时将多个目标文件组合在一起形成一个可执行文件的过程。

这个过程包括两个部分:分别是空间和地址的分配以及符合解析和重定位;

1.空间与地址的分配过程中,首先会扫描所有的输入文件,获得他们的各个段的长度,属性和位置,然后将输入文件中所有的符号定义和符号引用收集起来,统一放到一个全局符号表中,在合并相应的段,计算出合并后的段的长度和位置,并建立相应的映射关系。



2.符号解析与符号重定位:这个过程是链接的核心,它读入输入文件中的段信息,重定位信息,并进行符号解析和重定位,调整代码中的地址,进而完成链接。

什么是动态链接

动态链接的引入是为了解决静态链接过程中的空间浪费以及程序库升级不方便的问题,它本质上是一种加载时链接的技术,把程序的符号解析和重定位推迟到加载的时候再进行。

动态链接的地址无关技术

链接中重要的一个问题就是重定位,即修改代码段,将全局变量和外部函数的地址替换成运行时的真实地址,在动态链接中,采用了地址无关代码技术,该技术的主要思想是把代码段中跟地址相关的部分放到数据段中,使得重定位时,代码段不需要被修改。这个思想依赖于下面两个事实:

1.无论何处加载一个共享库,其数据段总是紧跟在代码段之后的,即代码段中任何指令和数据段中任何变量之间的距离都是一个常量,与代码段和数据段的绝对地址无关。

2.目标模块的数据段,在各个进程中都有对应的副本,是可以被修改的。

于是,编译器在数据段开始的地方创建了一个全局偏移量表,记录了该模块外所有外部函数或全部变量的表目,同时为全局偏移量表中每个表目生成一个重定位记录,在加载时,动态链接器更新GOT中表目的值,使得其值为该符号的运行时绝对地址。

函数的延迟绑定

动态链接中一个降低程序性能的原因是动态链接的工作是在加载时完成的,即程序启动后动态链接库要完成链接过程,即需要寻找并加在所需的共享库,进行符号搜索和重定位,这样无疑会影响程序的启动速度,于是就有了延迟绑定技术。

静态库和动态库的区别

首先文件的后缀不一样,在Linux系统中静态库的文件后缀为.a,动态库的文件后缀为.so

静态库文件的大小较大,动态库文件的大小较小;

静态库是将库中的代码拷贝到自己的代码中,这样将自己的代码拷贝到哪里都可以运行;

Linux下使用GCC如何生成静态库和动态库

生成静态库文件

在生成静态库文件前,我们首先要通过指令 gcc -c xxx.o xxx.c生成产生静态库文件的输入文件。

然后,我们通过 ar cr libxxx.a xxx.o生成静态库文件(图片静态库)。

随后就是通过gcc链接生成可执行文件,通过gcc -o xxx test.c -static -lxxx -L.

注意首先必须是静态链接,所以要加-static选项,然后又因为我们是在当前目录下生成的静态库文件,所以我们加上-L.选项使gcc在当前目录下寻找静态库文件。

整个过程如下图所示:



生成动态库可执行程序

在动态链接可执行程序前,首先我们要生成动态库文件,我们可以使用gcc -shared -fPIC -o libxxx.so xxx.o生成动态库文件;

然后,我们进行链接过程生成可执行文件 gcc -o xxx test.c -lxxx -L.

我们先来看看结果:



我们发现动态库libMyAdd.so文件成功生成,但是程序却无法执行。

因为动态库是在函数被调用时进行链接的,所以说明这是gcc可能还没有找到相关的链接文件。

这是因为gcc对动态库的查找是根据环境变量LD_LIBRARY_PATH中所指定的路径来进行查找的,由于我们的动态库生成在当前目录下,所以我们还没有把当前目录添加到环境变量中,所以无法找到动态库文件。

我们添加后来查看下结果:



我们发现这是动态链接的文件执行没有任何问题了~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息