2.5.2 符号解析
如果说地址空间分配是为段指定地址的话,那么符号解析就是为段内的符号指定地址。对于一个汇编文件来说,它内部使用的符号分为两类:一类来自自身定义的符号,称为内部符号。内部符号在其段内的偏移是确定的,当段的起始地址指定完毕后,内部符号的地址按照如下方式计算:
符号地址 = 符号所在段基址 + 符号所在段内偏移
另一类来自其他文件定义的符号,本地文件只是使用该符号,这类符号称为外部符号。外部符号地址在本地文件内是无法确定的,但是外部符号总定义在其他文件中。外部符号相对于定义它的文件就是内部符号了,同样使用前面的方式计算出它的地址,而使用该符号的本地文件需要的也是这个地址。
在重定位目标文件内,符号表记录了符号的所有信息。对于本地定义的符号,符号表项记录符号的段内偏移地址。对于外部引用的符号,符号表项标识该符号为“未定义的”。当链接器扫描到定义该外部符号的目标文件时,就需要将该外部符号的地址修改为正确的符号地址。最终的结果使得所有目标文件内的符号信息,无论是本地定义的还是外部定义的都是完整的、正确的。
链接器在扫描重定位目标文件的符号表时会动态地维护两个符号集合。一个记录所有文件定义的全局符号集合Export,该集合内的所有符号允许被其他文件引用。还有一个记录所有文件使用的未定义符号的集合Import,该集合内所有符号都来源于其他目标文件。文件扫描完毕后,链接器需要验证Import集合是否是Export的子集。如果不是,就表明存在未定义的符号。未定义的符号信息是未知的,链接器无法进行后续的操作,因而会报错。如果验证成功,则表明所有文件引用的外部符号都已定义,链接器才会将已定义的符号信息拷贝到未定义符号的符号表项。
符号解析完毕后,所有目标文件符号表内的所有符号都获得了完整、正确的符号地址信息。比如图2-18内的符号var、ext和fun在符号解析后的符号地址分别为0x080490f4、0x080490f8和0x080480cc。