程序运行之动态链接一

相比静态链接,动态链接要复杂得多。但比静态链接更能节省空间。而且对于软件的升级以及插件的使用更快,更方便。比如在静态链接中有一个公共模块common.o 占据1M的空间,使用到common.o模块的程序有100个,那么每个都需要链接common.o。也就是会占据100M空间。如果有更多这样的程序,就会浪费更多的空间。再比如在软件升级的场景,common.o是第三方开发的,当第三方对该模块进行更新的时候,所有包含了common.o的模块都必须重新获取,链接然后发布。也就是程序任何一个位置的改动都会导致程序重新下载。

而动态链接就可以解决上面的这些问题,动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完成的程序,而不是象静态链接一样把所有的程序模块都链接成一个单独的可执行文件。Windows下的动态链接文件是.dll为后缀名的文件,Linux下的动态链接文件是.so为后缀名的文件。

来用一个例子看下动态链接是如何工作的。创建pro1.c,pro2.c,Lib.c,Lib.h

pro1.c

#include "Lib.h"

int main()

{

                 foobar(1);

                 return 0;

}

pro2.c

#include "Lib.h"

int main()

{

                 foobar(2);

                 return 0;

}

Lib.c

#include <stdio.h>

void foobar(int i)

{

                 printf("Printing from Lib.so %d ",i);

}

可以看到pro1.c和pro2.c都使用到了Lib.c中的foobar函数,那么就可以将Lib.c打包成一个共享库

执行gcc -fPIC -shared -o Lib.so Lib.c后,生成Lib.so文件

gcc -o pro1 pro1.c ./Lib.so和gcc -o pro2 pro2.c ./Lib.so进行链接.这里和静态链接不一样,pro1.c被链接成可执行文件的这一步,在静态链接中,这一步链接过程会把pro1.o 和Lib.o链接到一起产生可输出执行文件,但是在这里,Lib.o没有链接进来,链接的输入目标文件只有pro1.o

运行结果如下:

./pro1

Printing from Lib.so 1

./pro2

Printing from Lib.so 2

当pro1.c被编译成pro1.o的时候,编译器不知道foobar函数的地址。如果foobar是一个定义与其他静态文件目标模块中的函数,那么链接器会按照静态链接的规则,将pro1.o中的foobar引用重定位。如果foobar是一个定义在某个动态共享对象里面,那么链接器就会将整个符号的引用标记为一个动态链接的符号,那么链接器是如何知道foobar引用的是一个静态还是动态的对象呢,这就是我们要用到Lib.so的原因。把Lib.so做为链接的输入文件之一,那么链接器就知道foobar是一个定义在Lib.so的动态符号

原文地址:https://www.cnblogs.com/zhanghongfeng/p/10758494.html