Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -162,9 +162,9 @@ scanEhFrameSection(EH, EH.template rels(), Fn); } -// We do not garbage-collect two types of sections: -// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr) -// 2) Non-allocatable sections which typically contain debugging information +// Some sections are used directly by the loader, so they should never be +// garbage-collected. This function returns true if a given section is such +// section. template static bool isReserved(InputSectionBase *Sec) { switch (Sec->Type) { case SHT_FINI_ARRAY: @@ -173,9 +173,6 @@ case SHT_PREINIT_ARRAY: return true; default: - if (!(Sec->Flags & SHF_ALLOC)) - return true; - StringRef S = Sec->Name; return S.startswith(".ctors") || S.startswith(".dtors") || S.startswith(".init") || S.startswith(".fini") || @@ -183,6 +180,27 @@ } } +// Returns true if a given section is a subject of garbage collection. +// The -gc-sections option works only for SHF_ALLOC sections +// (sections that are memory-mapped at runtime). So we can +// unconditionally make non-SHF_ALLOC sections alive. +// +// Non SHF_ALLOC sections are not removed even if they are +// unreachable through relocations because reachability is not +// a good signal whether they are garbage or not (e.g. there is +// usually no section referring to a .comment section, but we +// want to keep it.) +// +// Note on SHF_REL{,A}: Such sections reach here only when -r +// or -emit-reloc were given. And they are subject of garbage +// collection because, if we remove a text section, we also +// want to remove its relocation section. +static bool canBeCollected(InputSectionBase *Sec) { + bool IsAlloc = Sec->Flags & SHF_ALLOC; + bool IsRel = Sec->Type == SHT_REL || Sec->Type == SHT_RELA; + return IsAlloc || IsRel; +} + // This is the main function of the garbage collector. // Starting from GC-root sections, this function visits all reachable // sections to set their "Live" bits. @@ -198,8 +216,9 @@ if (Sec == &InputSection::Discarded) return; - // We don't gc non alloc sections. - if (!(Sec->Flags & SHF_ALLOC)) + // Not all sections are subject of garbage collection. We do not want + // to GC non-allocatable sections except SHF_REL{,A}. + if (!canBeCollected(Sec)) return; // Usually, a whole section is marked as live or dead, but in mergeable @@ -272,26 +291,11 @@ return; } - // The -gc-sections option works only for SHF_ALLOC sections - // (sections that are memory-mapped at runtime). So we can - // unconditionally make non-SHF_ALLOC sections alive. - // - // Non SHF_ALLOC sections are not removed even if they are - // unreachable through relocations because reachability is not - // a good signal whether they are garbage or not (e.g. there is - // usually no section referring to a .comment section, but we - // want to keep it.) - // - // Note on SHF_REL{,A}: Such sections reach here only when -r - // or -emit-reloc were given. And they are subject of garbage - // collection because, if we remove a text section, we also - // remove its relocation section. - for (InputSectionBase *Sec : InputSections) { - bool IsAlloc = (Sec->Flags & SHF_ALLOC); - bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); - if (!IsAlloc && !IsRel) + // Sections that are not subject of garbage collection are + // always live. See more details in comment for canBeCollected(). + for (InputSectionBase *Sec : InputSections) + if (!canBeCollected(Sec)) Sec->Live = true; - } // Follow the graph to mark all live sections. doGcSections(); Index: test/ELF/emit-relocs-gc.s =================================================================== --- test/ELF/emit-relocs-gc.s +++ test/ELF/emit-relocs-gc.s @@ -1,18 +1,30 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -## Show that we emit .rela.bar when GC is disabled. +## Show that we emit .rela.bar and .rela.text when GC is disabled. # RUN: ld.lld --emit-relocs %t.o -o %t # RUN: llvm-objdump %t -section-headers | FileCheck %s --check-prefix=NOGC +# NOGC: .rela.text # NOGC: .rela.bar -## GC collects .bar section and we exclude .rela.bar from output. +## GC collects .bar section and we exclude .rela.bar from output. We keep +## .rela.text because we keep .text. # RUN: ld.lld --gc-sections --emit-relocs --print-gc-sections %t.o -o %t \ # RUN: | FileCheck --check-prefix=MSG %s # MSG: removing unused section from '.bar' in file # MSG: removing unused section from '.rela.bar' in file # RUN: llvm-objdump %t -section-headers | FileCheck %s --check-prefix=GC # GC-NOT: rela.bar +# GC: rela.text +# GC-NOT: rela.bar .section .bar,"a" .quad .bar + +.text +relocs: +.quad _start + +.global _start +_start: + nop