链接
编译
在unix系统中, 由编译器把源文件转换为目标文件:
代码语言:javascript复制gcc -o hello hello.c
过程如下:
- 预处理: 处理以#开头的预处理命令
- 编译: 翻译成汇编文件
- 汇编: 将汇编文件翻译成可重定向目标文件
- 链接: 将可重定向目标文件和其他单独预编译好的目标文件合并, 最终得到可执行文件.
静态链接
静态链接器以一组可重定向目标文件为输入, 生成一个完全链接的可执行目标文件作为输出. 链接器主要完成两个任务:
- 符号解析: 每个符号对应一个函数, 一个全局变量, 或者一个静态变量, 符号解析的目的是将每个符号引用与一个符号定义关联起来.
- 重定位: 链接器通过把每个符号定义与一个内存位置关联起来, 然后修改所有对这些符号的引用, 使得他们指向这个内存位置.
目标文件
- 可执行目标文件: 可以直接在内存中执行
- 可重定向目标文件: 可与其他重定向目标文件在链接阶段合并, 创建一个可执行目标文件.
- 共享目标文件: 是一种特殊的可重定向目标文件, 可以在运行时被动态加载进内存并链接.
动态链接
静态库存在下列两个问题:
- 当静态库更新时那么整个冲虚都需要重新进行链接
- 对于printf这种标准函数库, 如果每个程序都要有代码, 那么会极大的浪费资源.
共享库是为了解决静态库的这两个问题而设计的, 在Linux系统中用.so后缀表示, 在windows上被称为dll. 他具有以下特点:
- 在给定的文件系统中一个库只有一个文件, 所有引用该库的可执行目标都共享这个文件, 他不会被复制到引用他的可执行文件中.
- 在内存中, 一个共享库.text节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享.