静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。为了构造可执行文件,链接器必须完成两个主要任务:
1、符号解析:目标文件定义和引用符号,符号解析将每个符号引用刚好和一个符号定义联系起来
2、重定位:编译器和汇编器生成从地址0开始的代码和数据section,链接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置
目标文件三种形式:可重定位目标文件、可执行目标文件、共享目标文件。编译器和汇编器生成可重定位目标文件(包括共享目标文件),链接器生成可执行目标文件。
现代UNIX系统的目标文件格式是ELF格式(executable and linkable Format)
一个典型的ELF可重定位目标文件包含下面几个段(section):
.text: 已编译程序的机器代码
.data: 已初始化的全局c变量,局部c变量在运行时保存在栈中,既不出现在.data段中,也不出现在.bss段中
.bss: 未初始化的全局c变量,在目标文件中这个段不占据实际的空间,它仅仅是一个占位符,目标文件格式区分初始化和未初始化变量是为了空间效率,在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。
.symtab: 一个符号表,存放在程序中定义和引用的函数和全局变量的信息。
每个可重定位目标模块m都有一个符号表,它包含模块所定义和引用的符号的信息,在链接器的上下文中,有三种不同的符号:
1、由m定义并能被其他模块引用的全局符号,对应于非静态的c函数以及被定义为不带static属性的全局变量
2、由其他模块定义并被模块m引用的全局符号,对应于定义在其他模块中的c函数和变量
3、只被模块m定义和引用的本地符号,对应于带static属性的c函数和全局变量,这些符号在本模块到处都可以访问,但是不能被其他模块引用。
注意,定义为带有static属性的本地局部变量不在栈中管理,编译器在.data和.bss中为每个定义分配空间,并在符号表中创建一个有唯一名字的本地链接器符号。
c语言中static属性在模块内部隐藏变量和函数声明,类似c++中public和private声明一样。c源代码文件扮演模块的角色,任何声明带有static属性的全局变量或者函数都是模块私有的,任何声明为不带static属性的全局变量和函数都是公共的,可以被其他模块访问。
c++和Java中能使用重载函数,是因为编译器将每个唯一的方法和参数列表组合编码成一个对链接器来说唯一的名字,这个编码过程为mangling,相反的过程为demangling