diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index c545a8bb9bb6..3f8b2248e90c 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -71,6 +71,12 @@ template static bool isReserved(InputSectionBase *Sec) { 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"); diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 0e0fb554c8d6..d7047b0b720b 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -24,6 +24,19 @@ using namespace llvm::ELF; 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) diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index e6538e82f056..34b106e7381f 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -55,6 +55,8 @@ getLocalRelTarget(const ObjectFile &File, 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. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index d60d8ea981f0..e87ebdfe7cb2 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1158,19 +1158,6 @@ template void Writer::addStartEndSymbols() { 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, diff --git a/lld/test/ELF/gc-sections-local-sym.s b/lld/test/ELF/gc-sections-local-sym.s index f864be38047f..5102e3050773 100644 --- a/lld/test/ELF/gc-sections-local-sym.s +++ b/lld/test/ELF/gc-sections-local-sym.s @@ -6,7 +6,7 @@ .global foo foo: -.section bar,"a" +.section .bar,"a" zed: // CHECK: Name: .strtab diff --git a/lld/test/ELF/startstop-gccollect.s b/lld/test/ELF/startstop-gccollect.s new file mode 100644 index 000000000000..b0cd41337e34 --- /dev/null +++ b/lld/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