From 12737b7f7290218e93ac658d1ea24f7adf997143 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Thu, 25 Feb 2016 08:40:26 +0000 Subject: [PATCH] [ELF] - Referencing __start or __stop should keep the section from GC. This fixes the https://llvm.org/bugs/show_bug.cgi?id=22906 bug. In GNU Binutils, a reference to start or stop is sufficient to prevent the section from being garbage collected. Patch implements the same behavior for lld. Differential revision: http://reviews.llvm.org/D17502 llvm-svn: 261840 --- lld/ELF/MarkLive.cpp | 6 ++++++ lld/ELF/OutputSections.cpp | 13 +++++++++++ lld/ELF/OutputSections.h | 2 ++ lld/ELF/Writer.cpp | 13 ----------- lld/test/ELF/gc-sections-local-sym.s | 2 +- lld/test/ELF/startstop-gccollect.s | 32 ++++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 lld/test/ELF/startstop-gccollect.s diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index c545a8bb9bb63..3f8b2248e90c6 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 0e0fb554c8d6e..d7047b0b720b1 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 e6538e82f0562..34b106e7381f0 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 d60d8ea981f05..e87ebdfe7cb2d 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 f864be38047fb..5102e30507739 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 0000000000000..b0cd41337e345 --- /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