文章目录
- 一、程序的编译过程
- 二、静态链接
- 三、目标文件
- 四、动态链接
一、程序的编译过程
在linux上编译一个c文件hello.c的命令为:
g++ -o hello hello.c
整个过程大致要经过一下四步:
- 预处理 : 处理以#开头的预处理命令
- 编译 : 翻译成汇编文件
- 汇编 : 将汇编文件翻译成可重定位的目标文件
- 链接 : 将可重定位目标文件和printf.o等单独预编译好的目标文件进行合并得到最终的可执行文件
二、静态链接
静态链接以一组可重定位目标.o文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下俩个任务:
- 符号解析: 每一个符号对应一个函数,一个全局变量或者一个静态变量,符号解析的目的是将每一个符号引用和一个符号定义关联起来。
- 重定位: 链接器通过把每一个符号定义和一个内存位置关联起来,然后修改所有对这些符号的引用,使得他们指向这个内存位置。
其实上图是有一点小错误的,在gcc中,链接是和系统库一起进行链接,但是你同样可以单独对可重定位目标文件.o文件进行单独"链接",比如调用ldstatic工具,此时,他不会和系统哭一起进行链接。
链接的最重要的目的就是为程序中的函数,全局变量,静态变量等提供虚拟内存中的地址,操作系统在装载程序的时候只有根据这些虚拟地址才能正确执行,否则会出现段错误。
具体的请参考这篇博客,写的相当好 : https://blog.csdn.net/qq_35102066/article/details/103075119
三、目标文件
可执行目标文件:可以直接在内存中执行;
可重定位目标文件:可与其它可重定位目标文件在链接阶段合并,创建一个可执行目标文件;
共享目标文件:这是一种特殊的可重定位目标文件,可以在运行时被动态加载进内存并链接;
四、动态链接
静态库存在以下问题:
- 当静态库需要更新的时候整个程序都要重新进行链接
- 对于printf这种标准函数库,如果每一个程序都要有代码,就会极大浪费资源。
共享库是为了解决静态库的这两个问题而设计的,在linux系统中通常用.so后缀来表示,windows系统上他们被称为DLL。动态库具有以下特点:
- 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中,从而节省资源。
- 在内存中,一个共享库的.text节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。