本章主要内容:数据结构
连接——静态连接、动态连接(连接又包括两个主要任务:符号解析和重定位)
符号——全局符号和本地符号、符号表、符号解析
连接文件的建立及引用——gcc、ar rcs、sharedj及fPIC命令参数
重定位——重定位条目、重定位符号引用(PC相对引用和绝对引用)
目标文件——可重定位目标文件(其中又详细介绍了ELF可重定位文件的结构及格式)、可执行目标文件、共享目标文件
连接(linking)是将各类代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行。
连接能够执行于编译时,即源代码被翻译成机器代码时;也可执行于加载时,即在程序被加载器加载到存储器并执行时;甚至执行于运行时,由应用程序来执行。
大多数编译系统提供编译器驱动程序(compiler driver),它表明用户在须要时调用语言预处理器、编译器、汇编器和连接器。函数
GNU编译系统编译源码:工具
Unix的静态连接器(static linker)ld,以一组可重位目标文件和命令行参数做为输入,生成一个彻底连接的能够加载和运行的可执行目标文件做为输出。输入的可重定位目标文件由各类不一样的代码和数据节(section)组成。指令在一个节中,初始化的全局变量在另外一个节中,而未初始化的变量又在另一个节中。编码
为了构造可执行文件,连接器必须完成两个主要任务:spa
目标文件有三种形式:可重定位目标文件。能够在编译时与其它可重定位目标文件合并起来,建立一个可执行目标文件。操作系统
编译器和汇编器生成可重定位目标文件(包括共享目标文件)。连接器生成可执行目标文件。
现代Unix系统使用可执行和可连接格式(ELF)。
可重定位目标文件命令行
一个典型的可重定位目标文件包含下面几个节:
.text:已编译程序的机器代码。
.rodata:只读数据。
.data:已初始化的全局C变量。局部C变量在运行时保存在栈中,既不出如今.data节中,也不出如今.bss节中。
.bss:未初始化的全局C变量。翻译
每一个可重定位目标模块m都有一个符号表,它包含m所定义和引用的符号的信息。3d
弱符号:未初始化的全局变量code
规则:
规则1:不容许有多个强符号。 规则2:若是有一个强符号和多个弱符号,那么选择强符号。 规则3:若是有多个弱符号,那么从这些弱符号中任意选择一个。
全部的编译系统都提供一种机制,将全部相关的目标模块打包成为一个单独的文件,称为静态库(Linux下是存档文件,Windows下是lib),能够用作连接器的输入。
C程序开始时是一组ASCII文本文件,已经被转化为一个二进制文件,且这个二进制文件包含加载程序到存储器并运行它所需的全部信息。
段头部表:可执行文件的连续片被映射到连续的存储器段,段头部表描述了这种关系。
加载器将可执行目标文件中的执行代码和数据从磁盘拷贝到存储器中,而后经过跳转到程序的第一条指令或入口点来运行该程序。这个将程序拷贝到存储器并运行的过程叫作加载。
用户栈老是最大的合法用户地址开始,向下增加的(向低存储器地址方向增加)。从栈的上部开始的段是为操做系统驻留存储器的部分(也就是内核)的代码和数据保留的。
接下来,加载器跳转到程序的入口点,也就是符号_start的地址。在_start地址处的启动代码(startup code)是在目标文件ctrl.o中定义的,对全部的C程序都是同样的。
编译库代码,使得不须要连接器修改库代码就能够在任何地址加载和执行这些代码。
-fPIC
选项指示GNU生成PIC代码