Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -105,6 +105,10 @@ // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; + // Keeps sections that belongs to COMDAT groups, used for -r. Each section + // that belongs to group should be placed to separate output section. + llvm::DenseSet GroupedSections; + protected: InputFile(Kind K, MemoryBufferRef M); std::vector Sections; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -278,6 +278,7 @@ this->SectionStringTable = check(Obj.getSectionStringTable(ObjSections), toString(this)); + std::vector Groups; for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) continue; @@ -304,8 +305,10 @@ // exception is the -r option because in order to produce re-linkable // object files, we want to pass through basically everything. if (IsNew) { - if (Config->Relocatable) + if (Config->Relocatable) { this->Sections[I] = createInputSection(Sec); + Groups.push_back(&Sec); + } continue; } @@ -332,6 +335,10 @@ this->Sections[I] = createInputSection(Sec); } + for (const Elf_Shdr *Sec : Groups) + for (uint32_t Ndx : getShtGroupEntries(*Sec)) + GroupedSections.insert(this->Sections[Ndx]); + // .ARM.exidx sections have a reverse dependency on the InputSection they // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. if (Sec.sh_flags & SHF_LINK_ORDER) { Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -212,7 +212,10 @@ // dedup'ed section groups by their signatures. For the -r, we want to pass // through all SHT_GROUP sections without merging them because merging them // creates broken section contents. - if (IS->Type == SHT_GROUP) { + // We also do not merge any sections belonging to groups because otherwise we + // end up with multiple SHT_GROUPs containing the same output section. + if (IS->Type == SHT_GROUP || + (IS->File && IS->File->GroupedSections.count(IS))) { OutputSection *Out = nullptr; addInputSec(IS, OutsecName, Out); return; Index: test/ELF/relocatable-comdat2.s =================================================================== --- test/ELF/relocatable-comdat2.s +++ test/ELF/relocatable-comdat2.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -r %t.o -o %t +# RUN: llvm-readobj -elf-section-groups %t | FileCheck %s + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: bar +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .foo (3) +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: zed +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .foo (5) +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .foo,"axG",@progbits,bar,comdat +.section .foo,"axG",@progbits,zed,comdat