链接器必须对这些可重定位目标文件完成两个主要任务:
-
符号解析。将每个符号引用刚好和一个符号定义联系起来。
-
重定位。链接器把每个符号定义与一个虚拟地址联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储位置,从而重定位这些节。
符号分为四类: 导出符号(export,本地符号), 导入符号(import,外部符号), 静态符号(本地符号), 局部符号(本地符号,不出现在符号表中)。
导出符号, 在本模块定义, 能够被其他模块引用的符号。 非static全局函数, 非static全局变量。
导入符号, 在其他模块定义,被本模块引用的符号。 extern 修饰的全局非static变量声明(extern int a), 其他模块的函数引用
静态符号, 在本模块定义, 只能被本模块引用的符号。 static函数, static全局变量。
局部符号, 在函数内部定义的非static变量。不出现在符号表,由栈管理。链接器不care这类符号
外部符号(导入符号): 本模块未定义却被本模块引用的符号。
汇编器生成可重定位目标文件后, 内部符号都已被正确地符号解析, 外部符号可能会引用了非本模块的符号定义,汇编器无法找到符号定义, 因此无法解析。 汇编器把外部符号放入”符号表“.symtab,同时把如何解析该符号的方法放入”重定位表“。
链接器符号解析:
使用的表: 符号表
强符号,若符号: 函数和初始化的全局变量叫强符号, 未初始化的全局变量叫弱符号。(extern int a是一个弱符号定义, int a 也是弱符号)
符号解析规则:
1, (定义多个强符号) 当引用符号时,该符号的符号定义有不止一个强符号定义时,会出现符号重定义错误。
2, (定义一个强符号和一个或者多个软符号)当引用符号时, 该符号的符号定义有个强符号定义和一个和多个弱符号定义, 使用强符号定义。
3, (定义多个弱符号)当引用符号时, 该符号的符号定义都是弱符号时, 选择任意一个定义。
链接器符号重定位:
使用的表: 重定位表,符号表
重定位表记录要修改的符号引用的位置,以及如何修改。
一旦链接器完成了符号解析这一步,它就把代码中的每个符号引用和确定的一个符号定义联系起来。此时,链接器就知道了每个模块(文件)代码节和数据节的大小,就可以开始重定位了。
重定位由三步组成:
-
合并可重定位目标文件中相同的节,
-
重定位节和符号定义,修改符号表。为节和符号定义分配虚拟地址。修改符号表中符号定义的值为刚分配的虚拟地址。
-
重定位节中的符号引用,修改代码段和数据段符号引用。使用重定位表.rel.text .rel.data, 修改text,data中符号引用的地址
简述为, 合并节, 重定位符号定义(修改符号表),重定位符号引用(修改数据段代码段)
汇编器遇到对存储位置未知(在可重定位目标文件中,汇编器都不知道数据和代码会存放在存储器的什么位置)的符号引用时,它也会将这些符号的信息存于.rel.text和.rel.data表中。告诉链接器将可重定位目标文件合并成可执行目标文件时如何修改符号引用。
阅读(2251) | 评论(0) | 转发(0) |