diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -207,8 +207,8 @@ void parse(bool ignoreComdats = false); - StringRef getShtGroupSignature(ArrayRef sections, - const Elf_Shdr &sec); + llvm::Optional getShtGroupSignature(ArrayRef sections, + const Elf_Shdr &sec); Symbol &getSymbol(uint32_t symbolIndex) const { if (symbolIndex >= this->symbols.size()) diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -416,12 +416,13 @@ initializeSymbols(); } -// Sections with SHT_GROUP and comdat bits define comdat section groups. -// They are identified and deduplicated by group name. This function -// returns a group name. +// The sh_info field of a SHT_GROUP section contains the symbol table index of +// the signature symbol. This function returns None if the signature is local, +// or a group name otherwise. template -StringRef ObjFile::getShtGroupSignature(ArrayRef sections, - const Elf_Shdr &sec) { +Optional +ObjFile::getShtGroupSignature(ArrayRef sections, + const Elf_Shdr &sec) { typename ELFT::SymRange symbols = this->getELFSyms(); if (sec.sh_info >= symbols.size()) fatal(toString(this) + ": invalid symbol index"); @@ -437,6 +438,9 @@ // a bug-compatibility. if (signature.empty() && sym.getType() == STT_SECTION) return getSectionName(sec); + + if (sym.getBinding() == STB_LOCAL) + return None; return signature; } @@ -607,7 +611,7 @@ switch (sec.sh_type) { case SHT_GROUP: { // De-duplicate section groups by their signatures. - StringRef signature = getShtGroupSignature(objSections, sec); + Optional signature = getShtGroupSignature(objSections, sec); this->sections[i] = &InputSection::discarded; ArrayRef entries = @@ -619,10 +623,11 @@ if (flag && flag != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); - bool keepGroup = - (flag & GRP_COMDAT) == 0 || ignoreComdats || - symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) - .second; + bool keepGroup = (flag & GRP_COMDAT) == 0 || ignoreComdats || + !signature || + symtab->comdatGroups + .try_emplace(CachedHashStringRef(*signature), this) + .second; if (keepGroup) { if (config->relocatable) this->sections[i] = createInputSection(sec); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -708,11 +708,13 @@ return msg; // If the discarded section is a COMDAT. - StringRef signature = file->getShtGroupSignature(objSections, elfSec); - if (const InputFile *prevailing = - symtab->comdatGroups.lookup(CachedHashStringRef(signature))) - msg += "\n>>> section group signature: " + signature.str() + - "\n>>> prevailing definition is in " + toString(prevailing); + if (Optional signature = + file->getShtGroupSignature(objSections, elfSec)) { + if (const InputFile *prevailing = + symtab->comdatGroups.lookup(CachedHashStringRef(*signature))) + msg += "\n>>> section group signature: " + signature->str() + + "\n>>> prevailing definition is in " + toString(prevailing); + } return msg; } diff --git a/lld/test/ELF/comdat-local.s b/lld/test/ELF/comdat-local.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/comdat-local.s @@ -0,0 +1,24 @@ +# REQUIRES: x86 +## If the signature symbol of a group is local, suppress COMDAT deduplication. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld %t.o %t.o -o %t +# RUN: llvm-readelf -s -x .zero -x .comdat %t | FileCheck %s + +# CHECK: NOTYPE LOCAL DEFAULT [[#A:]] zero +# CHECK-NEXT: NOTYPE LOCAL DEFAULT [[#B:]] comdat +# CHECK-NEXT: NOTYPE LOCAL DEFAULT [[#A]] zero +# CHECK-NEXT: NOTYPE LOCAL DEFAULT [[#B]] comdat + +# CHECK: Hex dump of section '.zero': +# CHECK-NEXT: [[#%x,_:]] 0202 +# CHECK: Hex dump of section '.comdat': +# CHECK-NEXT: [[#%x,_:]] 0101 + +.section .zero,"aG",@progbits,zero +zero: + .byte 2 + +.section .comdat,"aG",@progbits,comdat,comdat +comdat: + .byte 1