COMMON块

由于弱符号机制允许同一个符号的定义存在于多个文件中,所以可能会导致的一个问题是:如果一个弱符号定义在多个目标文件中,而它们的类型又不同,怎么办?目前的链接器本身并不支持符号的类型,即变量类型对于链接器来说是透明的,它只知道一个符号的名字,并不知道类型是否一致。当我们定义的多个符号定义类型不一致时,链接器如何处理呢?

事实上,现在的编译器和链接器都支持一种叫COMMON块的机制,这种机制最早来源于Fortan,早起的Fortan没有动态分配空间的机制,程序员必须事先声明它所需要的临时使用空间的大小。Fortan把这种空间叫COMMON块,当不同的目标文件需要的COMMON块空间大小不一致时,以最大的那块为准。

现代的链接机制在处理弱符号的时候,采用的就是与COMMON块一样的机制。编译器将未初始化的全局变量定义作为弱符号处理。

当然COMMON类型的链接规则是针对符号都是弱符号的情况,如果其中有一个符号为强符号,那么最终输出结果中的符号所占空间与强符号相同。如果链接过程中有弱符号大小大于强符号,那么ld链接器会报警告

这种使用COMMON块的方法实际上是一种类似“黑客”的取巧办法,直接导致需要COMMON机制的原因是编译器和链接器允许不同类型的弱符号存在,但最本质的原因还是链接器不支持符号类型,即链接器无法判断各个符号的类型是否一致。

通过了解链接器处理多个弱符号的过程,我们可以想到,当编译器将一个编译单元编译成目标文件的时候,如果该编译单元包含了弱符号(未初始化的全局变量就是典型的弱符号),那么该弱符号最终所占空间的大小在此时是未知的,因为有可能其他编译单元中该符号所占的空间比本编译单元该符号所占的空间要大。所以编译器此时无法为该弱符号在BSS段分配空间,因为所需要空间的大小未知。但是链接器在链接过程中可以确定弱符号的大小,因为当链接器读取所有输入目标文件以后,任何一个弱符号的最终大小都可以确定了,所以它可以再最终输出文件的BSS段为其分配空间。所以总体来看,未初始化全见谅最终还是被放在BSS段的。

GCC的“-fno-common”也允许沃恩把所有未初始化的全局变量不以COMMON块的形式处理,或者使用“__attribute__”拓展.

一旦一个未初始化的全局变量不是以COMMON块的形式存在,那么它就相当于一个强符号,如果其他目标文件中还有同一个变量的强符号定义,链接时就会发生符号重复定义错误。

原文地址:https://www.cnblogs.com/fr-ruiyang/p/10483397.html