Index: lld/trunk/ELF/MarkLive.cpp =================================================================== --- lld/trunk/ELF/MarkLive.cpp +++ lld/trunk/ELF/MarkLive.cpp @@ -71,6 +71,12 @@ return true; default: StringRef S = Sec->getSectionName(); + + // We do not want to reclaim sections if they can be referred + // by __start_* and __stop_* symbols. + if (isValidCIdentifier(S)) + return true; + return S.startswith(".ctors") || S.startswith(".dtors") || S.startswith(".init") || S.startswith(".fini") || S.startswith(".jcr"); Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -55,6 +55,8 @@ bool canBePreempted(const SymbolBody *Body, bool NeedsGot); +bool isValidCIdentifier(StringRef S); + // This represents a section in an output file. // Different sub classes represent different types of sections. Some contain // input sections, others are created by the linker. Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -24,6 +24,19 @@ using namespace lld; using namespace lld::elf2; +static bool isAlpha(char C) { + return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_'; +} + +static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); } + +// Returns true if S is valid as a C language identifier. +bool elf2::isValidCIdentifier(StringRef S) { + if (S.empty() || !isAlpha(S[0])) + return false; + return std::all_of(S.begin() + 1, S.end(), isAlnum); +} + template OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags) Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -1158,19 +1158,6 @@ Out::Dynamic->FiniArraySec); } -static bool isAlpha(char C) { - return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_'; -} - -static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); } - -// Returns true if S is valid as a C language identifier. -static bool isValidCIdentifier(StringRef S) { - if (S.empty() || !isAlpha(S[0])) - return false; - return std::all_of(S.begin() + 1, S.end(), isAlnum); -} - // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_ and // __stop_ symbols. They are at beginning and end of the section, Index: lld/trunk/test/ELF/gc-sections-local-sym.s =================================================================== --- lld/trunk/test/ELF/gc-sections-local-sym.s +++ lld/trunk/test/ELF/gc-sections-local-sym.s @@ -6,7 +6,7 @@ .global foo foo: -.section bar,"a" +.section .bar,"a" zed: // CHECK: Name: .strtab Index: lld/trunk/test/ELF/startstop-gccollect.s =================================================================== --- lld/trunk/test/ELF/startstop-gccollect.s +++ lld/trunk/test/ELF/startstop-gccollect.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +## Default run: sections foo and bar exist in output +# RUN: ld.lld %t -o %tout +# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s + +## Check that foo and bar sections are not garbage collected, +## we do not want to reclaim sections if they can be referred +## by __start_* and __stop_* symbols. +# RUN: ld.lld %t --gc-sections -o %tout +# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s + +# DISASM: _start: +# DISASM-NEXT: 11000: 90 nop +# DISASM-NEXT: Disassembly of section foo: +# DISASM-NEXT: foo: +# DISASM-NEXT: 11001: 90 nop +# DISASM-NEXT: Disassembly of section bar: +# DISASM-NEXT: bar: +# DISASM-NEXT: 11002: 90 nop + +.global _start +.text +_start: + nop + +.section foo,"ax" + nop + +.section bar,"ax" + nop