| commit 60ce444eaa146bc2f762c70d433d4a0c847508f0 |
| Author: Fangrui Song <maskray@google.com> |
| Date: Fri Dec 6 16:26:55 2019 -0800 |
| |
| [ELF] Refine section group --gc-sections rules to not discard .debug_types |
| |
| clang/gcc -fdebug-type-sections places .debug_types and |
| .rela.debug_types in a section group, with a signature symbol which |
| represents the type signature. The section group is for deduplication |
| purposes. |
| |
| After D70146, we will discard such section groups. Refine the rule so |
| that we will retain the group if no member has the SHF_ALLOC flag. |
| |
| GNU ld has a similar rule to retain the group if all members have the |
| SEC_DEBUGGING flag. We try to be more general for future-proof purposes: |
| if other non-SHF_ALLOC sections have deduplication needs, they may be |
| placed in a section group. Don't discard them. |
| |
| Reviewed By: grimar |
| |
| Differential Revision: https://reviews.llvm.org/D71157 |
| |
| diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp |
| index 7dc72361abd..d732f0d2564 100644 |
| --- a/lld/ELF/InputFiles.cpp |
| +++ b/lld/ELF/InputFiles.cpp |
| @@ -497,6 +497,42 @@ static void addDependentLibrary(StringRef specifier, const InputFile *f) { |
| specifier); |
| } |
| |
| +template <class ELFT> |
| +static void handleSectionGroup(ArrayRef<InputSectionBase *> sections, |
| + ArrayRef<typename ELFT::Word> 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 <class ELFT> |
| void ObjFile<ELFT>::initializeSections(bool ignoreComdats) { |
| const ELFFile<ELFT> &obj = this->getObj(); |
| @@ -615,26 +651,8 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) { |
| toString(linkSec)); |
| } |
| |
| - // For each secion group, connect its members in a circular doubly-linked list |
| - // via nextInSectionGroup. See the comment in markLive(). |
| - for (ArrayRef<Elf_Word> 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<Elf_Word> entries : selectedGroups) |
| + handleSectionGroup<ELFT>(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 |
| index 00000000000..959e10d4968 |
| --- /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 |
| index ad4e313f84e..8f713f5cf1e 100644 |
| --- 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 |