Index: lld/ELF/InputFiles.h =================================================================== --- lld/ELF/InputFiles.h +++ lld/ELF/InputFiles.h @@ -175,7 +175,6 @@ StringRef getShtGroupSignature(ArrayRef Sections, const Elf_Shdr &Sec); - ArrayRef getShtGroupEntries(const Elf_Shdr &Sec); public: static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -320,17 +320,6 @@ return Signature; } -template -ArrayRef::Elf_Word> -ObjFile::getShtGroupEntries(const Elf_Shdr &Sec) { - const ELFFile &Obj = this->getObj(); - ArrayRef Entries = - CHECK(Obj.template getSectionContentsAsArray(&Sec), this); - if (Entries.empty() || Entries[0] != GRP_COMDAT) - fatal(toString(this) + ": unsupported SHT_GROUP format"); - return Entries.slice(1); -} - template bool ObjFile::shouldMerge(const Elf_Shdr &Sec) { // On a regular link we don't merge sections if -O0 (default is -O1). This // sometimes makes the linker significantly faster, although the output will @@ -407,6 +396,8 @@ this->SectionStringTable = CHECK(Obj.getSectionStringTable(ObjSections), this); + SmallVector, 8> GroupDependencies; + for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) continue; @@ -438,32 +429,58 @@ switch (Sec.sh_type) { case SHT_GROUP: { - // De-duplicate section groups by their signatures. - StringRef Signature = getShtGroupSignature(ObjSections, Sec); - bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; - this->Sections[I] = &InputSection::Discarded; - // We only support GRP_COMDAT type of group. Get the all entries of the - // section here to let getShtGroupEntries to check the type early for us. - ArrayRef Entries = getShtGroupEntries(Sec); + const ELFFile &Obj = this->getObj(); + ArrayRef Entries = + CHECK(Obj.template getSectionContentsAsArray(&Sec), this); + + // We only support default and GRP_COMDAT type of group. + // default group members are unconditionnaly added to the target + if (Entries.empty() || (Entries[0] != GRP_COMDAT && Entries[0] != 0)) + fatal(toString(this) + ": unsupported SHT_GROUP format"); + + bool AddGroupMembers = true; + if(Entries[0] == GRP_COMDAT) { + // De-duplicate section groups by their signatures. + StringRef Signature = getShtGroupSignature(ObjSections, Sec); + AddGroupMembers = ComdatGroups.insert(CachedHashStringRef(Signature)).second; + this->Sections[I] = &InputSection::Discarded; + + } - // If it is a new section group, we want to keep group members. // Group leader sections, which contain indices of group members, are // discarded because they are useless beyond this point. The only // exception is the -r option because in order to produce re-linkable // object files, we want to pass through basically everything. - if (IsNew) { + else { + for (uint32_t SecIndex : Entries.slice(1)) { + if (SecIndex >= Size) + fatal(toString(this) + + ": invalid section index in group: " + Twine(SecIndex)); + // Model the sections inter-dependencies though DependentSections. + // Unfortunately, some references are forward references, so apply them later. + for (uint32_t GroupSecIndex : Entries.slice(1)) { + if(GroupSecIndex != SecIndex) { + GroupDependencies.emplace_back(SecIndex, GroupSecIndex); + } + } + } + } + + + // If it is a new section group, we want to keep group members. + if (AddGroupMembers) { if (Config->Relocatable) this->Sections[I] = createInputSection(Sec); - continue; } - - // Otherwise, discard group members. - for (uint32_t SecIndex : Entries) { - if (SecIndex >= Size) - fatal(toString(this) + - ": invalid section index in group: " + Twine(SecIndex)); - this->Sections[SecIndex] = &InputSection::Discarded; + else { + // Otherwise, discard group members. + for (uint32_t SecIndex : Entries.slice(1)) { + if (SecIndex >= Size) + fatal(toString(this) + + ": invalid section index in group: " + Twine(SecIndex)); + this->Sections[SecIndex] = &InputSection::Discarded; + } } break; } @@ -499,6 +516,17 @@ toString(LinkSec)); } } + + // Now that all sections are produced, store the dependencies implied + // by group sections. + for(auto const& Dep : GroupDependencies) { + uint32_t DepFrom = Dep.first; + uint32_t DepTo = Dep.second; + if(auto* DS = llvm::dyn_cast_or_null(this->Sections[DepTo])) { + if(this->Sections[DepFrom]) + this->Sections[DepFrom]->DependentSections.push_back(DS); + } + } } // For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD Index: lld/ELF/InputSection.cpp =================================================================== --- lld/ELF/InputSection.cpp +++ lld/ELF/InputSection.cpp @@ -92,12 +92,11 @@ } } -// Drop SHF_GROUP bit unless we are producing a re-linkable object file. -// SHF_GROUP is a marker that a section belongs to some comdat group. -// That flag doesn't make sense in an executable. -static uint64_t getFlags(uint64_t Flags) { +// Drop SHF_GROUP bit for non-note sections, unless we are producing +// a re-linkable object file. That flag doesn't make sense in an executable. +static uint64_t getFlags(uint64_t Flags, uint64_t Type) { Flags &= ~(uint64_t)SHF_INFO_LINK; - if (!Config->Relocatable) + if (!Config->Relocatable && Type != SHT_NOTE) Flags &= ~(uint64_t)SHF_GROUP; return Flags; } @@ -124,7 +123,7 @@ InputSectionBase::InputSectionBase(ObjFile &File, const typename ELFT::Shdr &Hdr, StringRef Name, Kind SectionKind) - : InputSectionBase(&File, getFlags(Hdr.sh_flags), + : InputSectionBase(&File, getFlags(Hdr.sh_flags, Hdr.sh_type), getType(Hdr.sh_type, Name), Hdr.sh_entsize, Hdr.sh_link, Hdr.sh_info, Hdr.sh_addralign, getSectionContents(File, Hdr), Name, SectionKind) { Index: lld/ELF/MarkLive.cpp =================================================================== --- lld/ELF/MarkLive.cpp +++ lld/ELF/MarkLive.cpp @@ -173,9 +173,11 @@ switch (Sec->Type) { case SHT_FINI_ARRAY: case SHT_INIT_ARRAY: - case SHT_NOTE: case SHT_PREINIT_ARRAY: return true; + case SHT_NOTE: + // Notes withing a group can be dismissed if the group is not live. + return !(Sec->Flags & SHF_GROUP); default: StringRef S = Sec->Name; return S.startswith(".ctors") || S.startswith(".dtors") || @@ -269,8 +271,9 @@ template void elf::markLive() { if (!Config->GcSections) { // If -gc-sections is missing, no sections are removed. - for (InputSectionBase *Sec : InputSections) + for (InputSectionBase *Sec : InputSections) { Sec->Live = true; + } // If a DSO defines a symbol referenced in a regular object, it is needed. for (Symbol *Sym : Symtab->getSymbols()) @@ -303,8 +306,10 @@ bool IsAlloc = (Sec->Flags & SHF_ALLOC); bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER); bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); - if (!IsAlloc && !IsLinkOrder && !IsRel) + bool IsNote = Sec->Type == SHT_NOTE; + if (!IsAlloc && !IsLinkOrder && !IsRel && !IsNote) { Sec->Live = true; + } } // Follow the graph to mark all live sections. Index: lld/ELF/OutputSections.cpp =================================================================== --- lld/ELF/OutputSections.cpp +++ lld/ELF/OutputSections.cpp @@ -92,6 +92,10 @@ Live = true; Type = IS->Type; Entsize = IS->Entsize; + // Group flag is no longer relevant at that point (?), at least for notes. + // FIXME: This is definitievly not the right place to do that. + if(!Config->Relocatable) + IS->Flags &= ~SHF_GROUP; Flags = IS->Flags; } else { // Otherwise, check if new type or flags are compatible with existing ones. Index: lld/test/ELF/non-comdat-group.test =================================================================== --- /dev/null +++ lld/test/ELF/non-comdat-group.test @@ -0,0 +1,55 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: ld.lld %t.o %t.o -o %t -r +# RUN: llvm-readobj -s %t | FileCheck %s + +# CHECK: Name: .text.foo +# CHECK: Name: .rela.text.foo + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .group + Type: SHT_GROUP + Link: .symtab + Info: foo + Members: + - SectionOrType: GRP_COMDAT + - SectionOrType: .text.foo + - SectionOrType: .text.bar + - SectionOrType: .note + - Name: .note + Type: SHT_NOTE + Flags: [ SHF_GROUP ] + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ] + - Name: .text.bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ] + - Name: .rela.text.foo + Type: SHT_RELA + Flags: [ SHF_INFO_LINK, SHF_GROUP ] + Link: .symtab + Info: .text.foo + Relocations: + - Offset: 0x0000000000000000 + Symbol: foo + Type: R_X86_64_64 + - Name: .rela.text.bar + Type: SHT_RELA + Flags: [ SHF_INFO_LINK, SHF_GROUP ] + Link: .symtab + Info: .text.bar + Relocations: + - Offset: 0x0000000000000000 + Symbol: bar + Type: R_X86_64_64 +Symbols: + Global: + - Name: foo + - Name: bar +