diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -506,6 +506,8 @@ this->sectionStringTable = CHECK(obj.getSectionStringTable(objSections), this); + SmallVector, 4> groups; + for (size_t i = 0, e = objSections.size(); i < e; ++i) { if (this->sections[i] == &InputSection::discarded) continue; @@ -546,6 +548,9 @@ if (entries.empty()) fatal(toString(this) + ": empty SHT_GROUP"); + // Save group entries for some post-processing. + groups.push_back(entries); + // The first word of a SHT_GROUP section contains flags. Currently, // the standard defines only "GRP_COMDAT" flag for the COMDAT group. // An group with the empty flag doesn't define anything; such sections @@ -609,6 +614,34 @@ " with SHF_LINK_ORDER should not refer a non-regular section: " + toString(linkSec)); } + + // The spec requires group entries to be inter-dependent, i.e. it's a + // discard-all or keep-all strategy. Implement that behavior for notes, so + // that notes are kept / discarded based on how the other group sections are + // handled. + for (ArrayRef entries : groups) { + SmallVector notes; + for (uint32_t secIndex : entries.slice(1)) { + if (!this->sections[secIndex] || + this->sections[secIndex] == &InputSection::discarded) + continue; + if (this->sections[secIndex]->type == SHT_NOTE) { + notes.push_back(cast(this->sections[secIndex])); + } + } + for (uint32_t secIndex : entries.slice(1)) { + if (!this->sections[secIndex] || + this->sections[secIndex] == &InputSection::discarded) + continue; + if (this->sections[secIndex]->type != SHT_NOTE) { + for (InputSection *note : notes) { + note->dependentSections.push_back( + cast(this->sections[secIndex])); + this->sections[secIndex]->dependentSections.push_back(note); + } + } + } + } } // For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -165,9 +165,10 @@ switch (sec->type) { case SHT_FINI_ARRAY: case SHT_INIT_ARRAY: - case SHT_NOTE: case SHT_PREINIT_ARRAY: return true; + case SHT_NOTE: + return sec->dependentSections.empty(); default: StringRef s = sec->name; return s.startswith(".ctors") || s.startswith(".dtors") || @@ -357,8 +358,10 @@ bool isAlloc = (sec->flags & SHF_ALLOC); bool isLinkOrder = (sec->flags & SHF_LINK_ORDER); bool isRel = (sec->type == SHT_REL || sec->type == SHT_RELA); + bool isDependentNote = + (sec->type == SHT_NOTE && !sec->dependentSections.empty()); - if (!isAlloc && !isLinkOrder && !isRel) + if (!isAlloc && !isLinkOrder && !isRel && !isDependentNote) sec->markLive(); } diff --git a/lld/test/ELF/sht-group-note.test b/lld/test/ELF/sht-group-note.test new file mode 100644 --- /dev/null +++ b/lld/test/ELF/sht-group-note.test @@ -0,0 +1,56 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: ld.lld %t.o -o %t0 --gc-sections +# RUN: llvm-readobj -S %t0 | FileCheck --check-prefix=CHECK-DEAD %s +# RUN: ld.lld %t.o -o %t1 --gc-sections --export-dynamic-symbol=foo +# RUN: llvm-readobj -S %t1 | FileCheck --check-prefix=CHECK-LIVE %s + +# CHECK-DEAD-NOT: Name: .note..text.foo +# CHECK-DEAD-NOT: Name: .text.foo +# CHECK-DEAD: Name: .note.bar + +# CHECK-LIVE: Name: .text +# CHECK-LIVE: Name: .note..text.foo +# CHECK-LIVE: Name: .note.bar + +--- !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: .note..text.foo + - Name: .note..text.foo + Type: SHT_NOTE + Flags: [ SHF_GROUP ] + Content: "DEAD" + - Name: .text.foo + 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: .note.bar + Type: SHT_NOTE + Flags: [ ] + Content: "BEEF" +Symbols: + - Name: foo + Binding: STB_GLOBAL + Type: STT_FUNC + Section: .text.foo + Size: 0x08 +