下面这张图,相信很多人已经很熟悉很熟悉了!!!
其中最后一个过程,链接可以
1 执行于编译时,也就是在源代码被翻译成机器代码时;
2 也可以执行于加载时,也就是在程序被加载器加载到存储器并执行时;
3 甚至可以执行于运行时,由应用程序来执行。所以说链接以上的顺序并不是绝对固定的!!!
4 更加详细的内容见:https://www.cnblogs.com/mickole/articles/3659112.html
接下来的内容主要还是围绕链接的一些比较深入的细节。
从传统静态链接到加载时的共享库的动态链接,以及到运行时的共享库的动态链接。
编译器驱动程序(其实就是上面的那一套流程)
用到的两个程序代码:
swap.c
/* $begin swap */
/* swap.c */
extern int buf[];
int *bufp0 = &buf[0];
int *bufp1;
void swap()
{
int temp;
bufp1 = &buf[1];
temp = *bufp0;
*bufp0 = *bufp1;
*bufp1 = temp;
}
/* $end swap */
main.c
/* $begin main */
/* main.c */
void swap();
int buf[2] = {
1, 2};
int main()
{
swap();
return 0;
}
/* $end main */
由预处理器(cpp)将main.c翻译成中间文件:main.i,接下来是编译器(cc1)将main.i翻译成汇编文件main.s。然后是汇编器(as)将main.s翻译成一个可重定位的目标文件main.o。最后由链接器(ld)将main.o和swap.o以及一些系统目标文件组合起来,创建可执行目标文件p
之后,shell调用系统中加载器
的函数,由它将可执行文件 p 中的代码和数据复制到内存,然后将控制转移到这个程序的开头。
静态链接器
静态链接器就是以一组**可重定位目标文件和命令行(这个其实就是前面的编译器和汇编器传过来的引导链接器和加载器的数据结构)**为输入,以一个完整的可执行文件为输出
可重定位目标文件:由各种不同的代码和数据节组成
,每一节都是一个连续的字节序列,指令在一节,初始化的全局变量在一节,未初始化的变量在另外一节.
链接器必须完成两个主要任务:
为了构造可执行文件,链接器必须完成以下的两件事:
① 符号解析(symbol resolution)。 目标文件定义和引用符号,每个符号对应于一个函数、