Content #
编译器在编译源代码时,会为无法在当前编译单元内找到定义的符号生成一个特定的符号表条目,同时把“为该符号寻找定义”这个重任交给链接器。而链接器在随后进行符号解析时,便会在包含有全部符号信息的全局符号表中进行搜索。
如果链接器在这个过程中找到了符号的多个定义,它便会按照一定的规则来进行解析。编译器在编译源代码时,会为每一个全局符号指定对应的“强弱”信息,并同时将其隐含地编码在符号对应的符号表条目中。通常来说,函数和已初始化的全局变量为强符号,而未初始化的全局变量则是弱符号。而链接器对符号定义的选择会根据如下规则进行:
- 如果有一个强符号和多个弱符号同名,则选择强符号;
- 如果有多个弱符号同名,则从这些弱符号中任意选一个(通常会选择其中类型占用空间最大的那个);比如目标文件A定义全局变量global为int型,占4个字节;目标文件B定义 global为double型,占8个字节,那么目标文件A和B链接后,符号global占8 个字节(尽量不要使用多个不同类型的弱符号,否则容易导致很难发现的程序错误)。
- 如果存在多个强符号同名,则抛出链接错误。
符号之所以会有强弱之分,主要是为了做到这一点:当不确定某个符号是否被用户显式定义的情况下,链接器仍然可以选择使用对应的弱类型符号版本来编译程序。这种能力通常被用在各类框架中,以便为某类程序编译所依赖的代码部分提供默认实现。除此之外,在模块化的代码调试场景中(比如单元测试中的桩代码),当某个待测试模块的依赖模块还没有被实现时,链接器可以选用标记为弱类型的默认版本来编译程序。