diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -498,6 +498,42 @@ } template +static void handleSectionGroup(ArrayRef sections, + ArrayRef entries) { + bool hasAlloc = false; + for (uint32_t index : entries.slice(1)) { + if (index >= sections.size()) + return; + if (InputSectionBase *s = sections[index]) + if (s != &InputSection::discarded && s->flags & SHF_ALLOC) + hasAlloc = true; + } + + // If any member has the SHF_ALLOC flag, the whole group is subject to garbage + // collection. See the comment in markLive(). This rule retains .debug_types + // and .rela.debug_types. + if (!hasAlloc) + return; + + // Connect the members in a circular doubly-linked list via + // nextInSectionGroup. + InputSectionBase *head; + InputSectionBase *prev = nullptr; + for (uint32_t index : entries.slice(1)) { + InputSectionBase *s = sections[index]; + if (!s || s == &InputSection::discarded) + continue; + if (prev) + prev->nextInSectionGroup = s; + else + head = s; + prev = s; + } + if (prev) + prev->nextInSectionGroup = head; +} + +template void ObjFile::initializeSections(bool ignoreComdats) { const ELFFile &obj = this->getObj(); @@ -615,26 +651,8 @@ toString(linkSec)); } - // For each secion group, connect its members in a circular doubly-linked list - // via nextInSectionGroup. See the comment in markLive(). - for (ArrayRef entries : selectedGroups) { - InputSectionBase *head; - InputSectionBase *prev = nullptr; - for (uint32_t secIndex : entries.slice(1)) { - if (secIndex >= this->sections.size()) - continue; - InputSectionBase *s = this->sections[secIndex]; - if (!s || s == &InputSection::discarded) - continue; - if (prev) - prev->nextInSectionGroup = s; - else - head = s; - prev = s; - } - if (prev) - prev->nextInSectionGroup = head; - } + for (ArrayRef entries : selectedGroups) + handleSectionGroup(this->sections, entries); } // For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD diff --git a/lld/test/ELF/gc-sections-group-debug.s b/lld/test/ELF/gc-sections-group-debug.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/gc-sections-group-debug.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +## Check that group members are retained, if no member has the SHF_ALLOC flag. +## This rule retains .debug_types and .rela.debug_types emitted by clang/gcc. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld --gc-sections %t.o -o %t +# RUN: llvm-readobj -S %t | FileCheck %s + +# CHECK: Name: .debug_types + +.section .debug_types,"G",@progbits,abcd,comdat +.quad .debug_types diff --git a/lld/test/ELF/gc-sections-group.s b/lld/test/ELF/gc-sections-group.s --- a/lld/test/ELF/gc-sections-group.s +++ b/lld/test/ELF/gc-sections-group.s @@ -1,7 +1,7 @@ # REQUIRES: x86 ## Check that group members are retained or discarded as a unit, and -## non-SHF_ALLOC sections in a group are subject to garbage collection. -## This is compatible with GNU ld. +## non-SHF_ALLOC sections in a group are subject to garbage collection, +## if at least one member has the SHF_ALLOC flag. # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o # RUN: ld.lld --gc-sections %t.o -o %t.dead