链接

链接

1.回顾一下

链接

hello.c的编译过程:

①预处理器cpp     gcc -E hello.c  -o hello.i  (ascii码中间文件)

将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码

②编译器ccl          gcc -S hello.i   -o hello.s (ascii码汇编语言文件)

“翻译”成汇编代码

③汇编器as           gcc -c hello.s   -o hello.o  (可重定位目标文件)

汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现位ELF目标文件(OBJ文件)

④链接器ld           gcc     hello.o  -o hello    (可执行目标文件)

将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行程序 


2.链接器

链接

question1:为什么要用它?

①模块化

程序可以写成一组小规模的源代码,对于通用的功能写成库。例如Math library, standard C library。

②效率

时间上单独编译。一个源文件发生变化,单独编译,重新链接。

空间上:库。功能函数聚合为一个单独的文件,可执行文件仅包括其实际使用的代码。

question2:它做了什么?

①符号解析:

  • 在这个程序里面定义或者引用的符号(函数、变量)。
  • 符号表:保存符号定义(编译器干的),是一个结构数组,每个条目有符号名,大小,保存位置。
  • 链接器将符号引用符号定义关联起来。

②重定位

  • 各自的代码和数据段合并。
  • 符号的相对位置重定位到绝对存储位置
  • 更新所有符号引用到绝对位置。

 

a.目标文件有哪些

①可重定位目标文件

编译时可以与其他可重定位合并。

②可执行目标文件

可以直接复制到存储器并执行。

③共享目标文件

特殊的可重定位目标文件。可以在加载或运行时,动态地加载到存储器并链接。(windows内称为动态链接库)

链接

b.可执行和可链接格式ELF 

 目标文件的标准二进制格式,统一的格式。

链接

ELF header (16 字节的序列)

描述了生成该文件的系统的字的大小和字节顺序,剩下的部包含帮助链接器语法分析和解释目标文件的信息

 ELF 头的大小、目标文件的类型 (如可重定位、可执行或者是共享的)、机器类型(如 IA32) 、节头部表 (section header table) 文件偏移,以及节头部表中的条目大小和数量。

.text: 已编译程序的机器代码。

.rodata: 只读数据,比如 printf 语句中的格式串和开关语句的跳转表。

.data: 已初始化的全局变量。

.bss: 未初始化的全局变量。目标文件种不需要占据任何实际的磁盘空间。

.symtab: 符号表,存放在程序中定义和引用函数和全局变量的信息。和编译器中的符号表不同不包含局部变量的条目

. rel .text:  .text 节中位置的列表,链接器把这个目标文件和其他文件结合时,需要修改这些位置。可执行目标文件中并不需要重定位信息因此通 常省略,除非用户显式地指示链接器包含这些信息。

.rel.data: 被模块引用或定义的任何全局变量的重定位信息

.debug: 一个调试符号表,其条目是程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的源文件。以-g选项调用编译驱动程序时才会得到。

.line: 原始源程序中的行号和 .text 节中机器指令之间的映射。 -g 才会得到。

11.strtab: 一个字符串表,包括 .symtab .debug 节中的符号表,以及ELF header中的节名字。字符串表就是以 null 结尾的字符串序列。