[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
This commit is contained in:
Fangrui Song 2019-12-06 16:26:55 -08:00
parent f3a28202ef
commit 60ce444eaa
3 changed files with 52 additions and 22 deletions

View File

@ -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

View File

@ -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

View File

@ -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