Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -305,13 +305,22 @@ } switch (Sec.sh_type) { - case SHT_GROUP: - this->Sections[I] = &InputSection::Discarded; - if (ComdatGroups - .insert( - CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) - .second) + case SHT_GROUP: { + // We discard comdat sections usually. When -r we should not do that. We + // still do deduplication in this case to simplify implementation, because + // otherwise merging group sections together would requre additional + // regeneration of its contents. + bool New = ComdatGroups + .insert(CachedHashStringRef( + getShtGroupSignature(ObjSections, Sec))) + .second; + if (New && Config->Relocatable) + this->Sections[I] = createInputSection(Sec, SectionStringTable); + else + this->Sections[I] = &InputSection::Discarded; + if (New) continue; + for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + @@ -319,6 +328,7 @@ this->Sections[SecIndex] = &InputSection::Discarded; } break; + } case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/ELF/InputSection.h @@ -319,6 +319,8 @@ private: template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); + + void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -295,6 +295,24 @@ return S->kind() != Output; } +void InputSection::copyShtGroup(uint8_t *Buf) { + assert(this->Type == SHT_GROUP); + + ArrayRef From = getDataAs(); + uint32_t *To = reinterpret_cast(Buf); + + // First entry is a flag word, we leave it unchanged. + *To++ = From[0]; + + // Here we adjust indices of sections that belong to group as it + // might change during linking. + ArrayRef Sections = this->File->getSections(); + for (uint32_t Val : From.slice(1)) { + uint32_t Index = read32(&Val, Config->Endianness); + write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); + } +} + InputSectionBase *InputSection::getRelocatedSection() { assert(this->Type == SHT_RELA || this->Type == SHT_REL); ArrayRef Sections = this->File->getSections(); @@ -680,6 +698,13 @@ return; } + // If -r is given, linker should keep SHT_GROUP sections. We should fixup + // them, see copyShtGroup(). + if (this->Type == SHT_GROUP) { + copyShtGroup(Buf + OutSecOff); + return; + } + // Copy section contents from source object file to output file // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -112,6 +112,19 @@ Flags |= SHF_COMPRESSED; } +template static void finalizeShtGroup(OutputSection *Sec) { + // sh_link field for SHT_GROUP sections should contain the section index of + // the symbol table. + Sec->Link = InX::SymTab->OutSec->SectionIndex; + + // sh_link then contain index of an entry in symbol table section which + // provides signature of the section group. + elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); + assert(Config->Relocatable && Sec->Sections.size() == 1); + ArrayRef Symbols = Obj->getSymbols(); + Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); +} + template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); @@ -126,6 +139,11 @@ } uint32_t Type = this->Type; + if (Type == SHT_GROUP) { + finalizeShtGroup(this); + return; + } + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) return; @@ -355,7 +373,10 @@ return; } - uint64_t Flags = IS->Flags & ~(uint64_t)SHF_GROUP; + uint64_t Flags = IS->Flags; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + Index: lld/trunk/test/ELF/relocatable-comdat.s =================================================================== --- lld/trunk/test/ELF/relocatable-comdat.s +++ lld/trunk/test/ELF/relocatable-comdat.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -r %t.o %t.o -o %t +# RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s + +# CHECK: Name: .text.bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .text.foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: abc +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.bar +# CHECK-NEXT: .text.foo +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .text.bar,"axG",@progbits,abc,comdat +.quad 42 +.section .text.foo,"axG",@progbits,abc,comdat +.long 42