diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -141,6 +141,7 @@ bool includeInDynsym() const; uint8_t computeBinding() const; + bool isGlobal() const { return binding == llvm::ELF::STB_GLOBAL; } bool isWeak() const { return binding == llvm::ELF::STB_WEAK; } bool isUndefined() const { return symbolKind == UndefinedKind; } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -528,7 +528,13 @@ return false; } - return isWeak() && !other.isWeak(); + // Incoming STB_GLOBAL overrides STB_WEAK/STB_GNU_UNIQUE. -fgnu-unique changes + // some vague linkage data in COMDAT from STB_WEAK to STB_GNU_UNIQUE. Treat + // STB_GNU_UNIQUE like STB_WEAK so that we prefer the first among all + // STB_WEAK/STB_GNU_UNIQUE copies. If we prefer an incoming STB_GNU_UNIQUE to + // an existing STB_WEAK, there may be discarded section errors because the + // selected copy may be in a non-prevailing COMDAT. + return !isGlobal() && other.isGlobal(); } void elf::reportDuplicate(const Symbol &sym, InputFile *newFile, diff --git a/lld/test/ELF/comdat-binding.s b/lld/test/ELF/comdat-binding.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/comdat-binding.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: rm -rf %t && split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/g.s -o %t/g.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/w.s -o %t/w.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/u.s -o %t/u.o +# RUN: ld.lld -e 0 %t/w.o %t/u.o -o %t/w +# RUN: llvm-readelf -s %t/w | FileCheck %s --check-prefix=WEAK +# RUN: ld.lld -e 0 %t/u.o %t/w.o -o %t/u +# RUN: llvm-readelf -s %t/u | FileCheck %s --check-prefix=UNIQUE + +# RUN: ld.lld -e 0 %t/w.o %t/g.o -o %t/w +# RUN: llvm-readelf -s %t/w | FileCheck %s --check-prefix=WEAK + +# WEAK: NOTYPE WEAK DEFAULT [[#]] _ZZ1fvE1x +# UNIQUE: OBJECT UNIQUE DEFAULT [[#]] _ZZ1fvE1x + +#--- g.s +movq _ZZ1fvE1x@gotpcrel(%rip), %rax + +.section .bss._ZZ1fvE1x,"awG",@nobits,_ZZ1fvE1x,comdat +.globl _ZZ1fvE1x +_ZZ1fvE1x: + +#--- w.s +.section .bss._ZZ1fvE1x,"awG",@nobits,_ZZ1fvE1x,comdat +.weak _ZZ1fvE1x +_ZZ1fvE1x: + +#--- u.s +.section .bss._ZZ1fvE1x,"awG",@nobits,_ZZ1fvE1x,comdat +.type _ZZ1fvE1x, @gnu_unique_object +_ZZ1fvE1x: