Chap-4 Section 4.3 COMMON块

4.3 COMMON块
如果一个弱符号定义在多个目标文件中,而它们的类型又不同,怎么办?目前的链接器
类型并不支持符号的类型,即变量类型对于链接器而言是透明的,它只知道一个名字,并
不知道类型是否一致,那么当我们定义的多个符号类型不一致时,链接器该怎么处理呢?
主要分三种情况:
1.两个或者两个以上的强符号类型不一致
2.有一个强符号,其他都是弱符号,出现类型不一致
3.两个或者两个以上弱符号类型不一致

对于第一种情况而言,定义多个强符号本身就是违法的,链接器会报符号多重定义错误,
链接器处理的就是后两种情况。

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

现在的链接器在处理弱符号的时候,采用的就是与COMMON块一样的机制,我们以实例来说明
该机制。
假设有如下两个c文件:
//weak-s1.c
int var;
void f();
int main() {
var = 12;
f();
}

//weak-s2.c
double var;
void f() {
var = 321;
}

将这两个c文件链接成为最终的目标文件test,我们用readelf -s test读取目标文件的
符号表,如图4.2.12所示:


***图4.2.12***
从图中可以看出,变量var的最终大小为8个字节,所在段的下标为25,我们再用readelf -S test
读取目标文件的段表,如图4.2.13所示,下标为25的段正好是.bss段。


***图4.2.13***

在单个目标文件中,比如在weak-s1.o中,为什么不直接把未初始化的全局变量也当作
未初始化的局部静态变量一样处理,为它在.bss段分配空间,而是将其标记为一个COMMON
类型的变量?
通过了解编译器处理多个弱符号的过程,我们可以知道,当编译器将一个编译单元编译成
目标文件后,如果该编译单元包含了弱符号,那么该弱符号最终所占空间的大小在此时是
未知的,因为可能在其他编译单元中,该符号所占的空间比本编译单元该符号所占的空间
大,所以编译器此时无法为该弱符号在.bss段分配空间,因为所需要的空间大小未知,但是
链接器在链接过程中可以确定弱符号的大小,因为当链接器读取所有输入目标文件后,任何
一个弱符号的最终大小都可以确定,所以它可以在最终输出文件的.bss段为其分配空间,
所以总体来看,未初始化的全局变量最终还是被放在.bss段的。
比如,我们单独对weak-s1.c编译,然后用readelf -S weak-s1.o查看该目标文件的段表,如
图4.2.14所示:


***图4.2.14***
图中.bss段的大小为0,由此说明编译单元为未把该未初始化的全局变量放在.bss段。

原文地址:https://www.cnblogs.com/miaoyong/p/3508082.html