第七章 链接
链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行。链接可以执行于加载时,也就是在程序被加载器加载到内存并执行时;甚至执行于运行时,也就是由应用程序来执行。通过学习链接这个章节,我得知了一下几个好处:
1.理解链接器将帮助你构造大型程序;
2.理解连接器将帮助你避免一些危险的编程错误;
3.理解链接将帮助你理解语言的作用域规则是如何实现的;
4.理解链接将帮助你理解其他重要的系统概念。
本章节大致讲述了以下几个内容:
*编译器驱动程序:
- 大多数编译系统提供编译器驱动程序,它代表用户在需要时调用语言预处理器,编译器,汇编器和链接器。比如,要用GNU编译系统构造示例程序,就要通过在shell中输入下列命令来调用GCC驱动程序:
- linux>gcc -og -o prog mian.c sum.c
- 驱动程序首先运行C预处理器(cpp),它将C的源程序,main.c翻译成一个ASCII码的中间文件main.i:
- cpp [other arguments] main.c /tmp/main.i
- 接下来,驱动程序运行C编译器(ccl),它将mian.i翻译成一个ASCII汇编语言文件main.s:
- ccl /tmp/main.i -og 【other arguments】 -o/tmp/main.s
- 然后,驱动程序运行汇编器(as),它将main.s翻译成一个可重定位目标文件main.o:
- as 是【other arguments】 -o/tmp/main.o /tmp/main.s
- 驱动程序经过相同的过程生成sum.o.最后,它运行链接器程序ld,将main.o和sum.o以及一些必要的系统目标文件组合起来,创建一个可执行目标文件prog:
- ld -o prog 【system object files and args】/tmp/main.o /tmp/sum.o
- 要运行可执行文件prog,我们在Linux shell的命令行上输入他的名字:
- linux> ./prog
- shell调用操作系统中一个叫做加载器的函数,他将可执行文件prog中的代码和数据复制到内存,然后将控制转移到这个程序的开头。
静态链接:
为了构造可执行文件,链接器必须完成两个主要任务:
1,符号解析。目标文件定义和引用符号,每个符号对应于一个函数,一个全局变量或一个静态变量。符号解析的目的是将每个符号引用正好和一个符号定义关联起来。
2,重定位。编译器和汇编器生成从地址0开始的代码和数据节。链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,是的它们指向这个内存位置。链接器使用汇编器产生的重定位条目的详细指令,不加甄别地执行这样的重定位。
*符号、符号表和符号解析:
*每个可重定位目标模块m有一个符号表,它包含m定义和引用的符号的信息。在链接器的上下文中,有三种不同的符号:
1,由模块m定义并能被其他模块引用的全局符号。
2,由其他模块定义并被模块m引用的全局符号。
3,只被模块m定义和引用的局部符号。
符号表是由汇编器构造的,使用编译器输出到汇编语言,s文件中的符号。symtab节中包含ELF符号表。这张符号表包含一个条目的数组。下面这个程序展现了每个条目的格式:
typedef struct{
int name; /Stri