Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -359,6 +359,10 @@ // Builds section order for handling --symbol-ordering-file. llvm::DenseMap buildSectionOrder(); +// Returns true if section with given Flags and Type should be +// live for GC by default. +bool isLiveByDefault(uint64_t Flags, uint32_t Type); + } // namespace elf std::string toString(const elf::InputSectionBase *); Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -78,7 +78,7 @@ // Return true if a section with given section flags is live (will never be // GCed) by default. If a section can be GCed, this function returns false. -static bool isLiveByDefault(uint64_t Flags, uint32_t Type) { +bool elf::isLiveByDefault(uint64_t Flags, uint32_t Type) { // If GC is enabled, all memory-mapped sections are subject of GC. if (!Config->GcSections) return true; Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -164,7 +164,8 @@ // 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 +// 2) Non-allocatable sections which typically contain debugging information, +// except SHT_REL[A] sections. template static bool isReserved(InputSectionBase *Sec) { switch (Sec->Type) { case SHT_FINI_ARRAY: @@ -173,7 +174,7 @@ case SHT_PREINIT_ARRAY: return true; default: - if (!(Sec->Flags & SHF_ALLOC)) + if (isLiveByDefault(Sec->Flags, Sec->Type)) return true; StringRef S = Sec->Name; @@ -198,8 +199,8 @@ if (Sec == &InputSection::Discarded) return; - // We don't gc non alloc sections. - if (!(Sec->Flags & SHF_ALLOC)) + // We don't gc sections that should be live by default. + if (isLiveByDefault(Sec->Flags, Sec->Type)) return; // Usually, a whole section is marked as live or dead, but in mergeable Index: test/ELF/emit-relocs-gc.s =================================================================== --- test/ELF/emit-relocs-gc.s +++ test/ELF/emit-relocs-gc.s @@ -6,13 +6,24 @@ # RUN: llvm-objdump %t -section-headers | FileCheck %s --check-prefix=NOGC # 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