Red Hat 9下C未初始化数据重叠问题:除-fcommon外的解决方案?
Red Hat 9中多目标文件未初始化数据重叠链接错误的原因与解决方案
问题背景
自Unix/Linux诞生(至少从1970年起),C语言一直支持多个目标文件中的未初始化全局数据对象重叠,即便它们的大小不同。但在Red Hat 9中,这个传统特性出现异常,链接阶段会抛出重复定义的错误。
示例代码
k1.c
char overlay[1024]; int main(int argc, char *argv[]){ void xmain(); xmain(); }
k2.c
char overlay[1024]; int xmain(){ }
编译行为差异
- Red Hat 8编译正常:
[jon@rh8x ~]$ cc k1.c k2.c -o k
- Red Hat 9编译链接报错:
[jon@rhel9 ~]$ cc k1.c k2.c -o k /usr/bin/ld: /tmp/ccnCZBZM.o:(.bss+0x0): multiple definition of `overlay'; /tmp/cca4vlOT.o:(.bss+0x0): first defined here collect2: error: ld returned 1 exit status
使用-fcommon参数可临时解决问题,但该参数不被推荐,且可能在后续GCC版本中被移除。
原因分析
Red Hat 9默认搭载的GCC版本(GCC 10及以上)将-fno-common设为默认编译选项。
在早期GCC版本(如Red Hat 8使用的版本)中,未初始化的全局变量会被放入common段,链接器遇到多个同名的common段变量时,会自动合并它们(即便大小不同,最终取最大的那个的尺寸),这正是传统Unix/C支持的重叠特性。
而-fno-common选项会让未初始化的全局变量直接被放在.bss段,每个目标文件都会生成独立的变量定义,链接器遇到同名的.bss段变量时,就会判定为重复定义并报错。
替代解决方案(除-fcommon外)
- 显式区分定义与声明:在其中一个文件中保留变量的定义,另一个文件用
extern声明变量。比如修改k2.c:
extern char overlay[1024]; int xmain(){ }
若变量大小不同,可使用不指定大小的extern char overlay[];,只要代码的使用逻辑兼容大小差异即可。
- 使用弱符号:在其中一个文件的变量定义前添加
__attribute__((weak))属性,链接器会优先选择非弱符号的定义;如果所有同名变量都是弱符号,则会任选一个(通常取最大的尺寸)。比如修改k2.c:
__attribute__((weak)) char overlay[1024]; int xmain(){ }
- 跨语言场景适配:对于涉及Fortran、Cobol等语言的场景,需确保不同语言的符号处理逻辑对齐:
- Fortran中可通过
-fno-automatic或特定编译选项控制变量的common属性; - Cobol可调整编译选项让未初始化数据生成符合common机制的符号,或显式声明符号的链接类型。
- Fortran中可通过
内容的提问来源于stack exchange,提问作者Jon Power
相关产品推荐
相关产品推荐

