From 8ec77e64fcd419df30e09989bcba62c5cb9fd172 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 21 Apr 2016 22:00:51 +0000 Subject: [PATCH] ELF: Change how to handle KEEP linker script command. You can instruct the linker to not discard sections even if they are unused and --gc-sections option is given. The linker script command for doing that is KEEP. The syntax is KEEP(foo) where foo is a section name. KEEP commands are written in SECTIONS command, so you can specify the order of sections *and* which sections will be kept. Each sub-command in SECTIONS command are translated into SectionRule object. Previously, each SectionRule has `Keep` bit. However, if you think about it, this hid information in too deep in elements of a list. Semantically, KEEP commands aren't really related to SECTIONS subcommands. We can keep the section list for KEEP in a separate list. This patch does that. llvm-svn: 267065 --- lld/ELF/LinkerScript.cpp | 41 +++++++++++-------- lld/ELF/LinkerScript.h | 11 +++--- lld/test/ELF/linkerscript-sections-keep.s | 48 +++++++++++------------ 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index d16559f1a10a..6457bc338cf2 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -35,6 +35,8 @@ using namespace lld::elf; ScriptConfiguration *elf::ScriptConfig; +static bool matchStr(StringRef S, StringRef T); + static uint64_t getInteger(StringRef S) { uint64_t V; if (S.getAsInteger(0, V)) { @@ -159,17 +161,11 @@ static uint64_t evaluate(ArrayRef Tokens, uint64_t Dot) { } template -SectionRule *LinkerScript::find(InputSectionBase *S) { +StringRef LinkerScript::getOutputSection(InputSectionBase *S) { for (SectionRule &R : Opt.Sections) if (R.match(S)) - return &R; - return nullptr; -} - -template -StringRef LinkerScript::getOutputSection(InputSectionBase *S) { - SectionRule *R = find(S); - return R ? R->Dest : ""; + return R.Dest; + return ""; } template @@ -179,8 +175,10 @@ bool LinkerScript::isDiscarded(InputSectionBase *S) { template bool LinkerScript::shouldKeep(InputSectionBase *S) { - SectionRule *R = find(S); - return R && R->Keep; + for (StringRef Pat : Opt.KeptSections) + if (matchStr(Pat, S->getSectionName())) + return true; + return false; } template @@ -326,7 +324,7 @@ private: void readLocationCounterValue(); void readOutputSectionDescription(); - void readSectionPatterns(StringRef OutSec, bool Keep); + void readSectionPatterns(StringRef OutSec); const static StringMap Cmd; ScriptConfiguration &Opt = *ScriptConfig; @@ -497,10 +495,10 @@ void ScriptParser::readSections() { } } -void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) { +void ScriptParser::readSectionPatterns(StringRef OutSec) { expect("("); while (!Error && !skip(")")) - Opt.Sections.emplace_back(OutSec, next(), Keep); + Opt.Sections.emplace_back(OutSec, next()); } void ScriptParser::readLocationCounterValue() { @@ -523,19 +521,28 @@ void ScriptParser::readOutputSectionDescription() { Opt.Commands.push_back({SectionKind, {}, OutSec}); expect(":"); expect("{"); + while (!Error && !skip("}")) { StringRef Tok = next(); if (Tok == "*") { - readSectionPatterns(OutSec, false); + expect("("); + while (!Error && !skip(")")) + Opt.Sections.emplace_back(OutSec, next()); } else if (Tok == "KEEP") { expect("("); - next(); // Skip * - readSectionPatterns(OutSec, true); + expect("*"); + expect("("); + while (!Error && !skip(")")) { + StringRef Sec = next(); + Opt.Sections.emplace_back(OutSec, Sec); + Opt.KeptSections.push_back(Sec); + } expect(")"); } else { setError("unknown command " + Tok); } } + StringRef Tok = peek(); if (Tok.startswith("=")) { if (!Tok.startswith("=0x")) { diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index d076f357b7cb..88bc0ad5ce2e 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -30,17 +30,14 @@ template class OutputSectionBase; // This class represents each rule in SECTIONS command. class SectionRule { public: - SectionRule(StringRef D, StringRef S, bool Keep) - : Dest(D), Keep(Keep), SectionPattern(S) {} + SectionRule(StringRef D, StringRef S) + : Dest(D), SectionPattern(S) {} // Returns true if S should be in Dest section. template bool match(InputSectionBase *S); StringRef Dest; - // KEEP command saves unused sections even if --gc-sections is specified. - bool Keep = false; - private: StringRef SectionPattern; }; @@ -70,6 +67,10 @@ struct ScriptConfiguration { bool DoLayout = false; llvm::BumpPtrAllocator Alloc; + + // List of section patterns specified with KEEP commands. They will + // be kept even if they are unused and --gc-sections is specified. + std::vector KeptSections; }; extern ScriptConfiguration *ScriptConfig; diff --git a/lld/test/ELF/linkerscript-sections-keep.s b/lld/test/ELF/linkerscript-sections-keep.s index b77ac4c644f8..fae6383ca499 100644 --- a/lld/test/ELF/linkerscript-sections-keep.s +++ b/lld/test/ELF/linkerscript-sections-keep.s @@ -37,37 +37,35 @@ # RUN: .keep : { KEEP(*(.keep)) } \ # RUN: .nokeep : { *(.keep) }}" > %t.script # RUN: ld.lld --gc-sections -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | \ -# RUN: FileCheck -check-prefix=KEEP-AT-FIRST %s -# KEEP-AT-FIRST: Sections: -# KEEP-AT-FIRST-NEXT: Idx Name Size Address Type -# KEEP-AT-FIRST-NEXT: 0 00000000 0000000000000000 -# KEEP-AT-FIRST-NEXT: 1 .keep 00000004 0000000000000120 DATA -# KEEP-AT-FIRST-NEXT: 2 .temp 00000004 0000000000000124 DATA -# KEEP-AT-FIRST-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA -# KEEP-AT-FIRST-NEXT: 4 .symtab 00000060 0000000000000000 -# KEEP-AT-FIRST-NEXT: 5 .shstrtab 0000002d 0000000000000000 -# KEEP-AT-FIRST-NEXT: 6 .strtab 00000012 0000000000000000 +# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED1 %s +# MIXED1: Sections: +# MIXED1-NEXT: Idx Name Size Address Type +# MIXED1-NEXT: 0 00000000 0000000000000000 +# MIXED1-NEXT: 1 .keep 00000004 0000000000000120 DATA +# MIXED1-NEXT: 2 .temp 00000004 0000000000000124 DATA +# MIXED1-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA +# MIXED1-NEXT: 4 .symtab 00000060 0000000000000000 +# MIXED1-NEXT: 5 .shstrtab 0000002d 0000000000000000 +# MIXED1-NEXT: 6 .strtab 00000012 0000000000000000 ## The same, but now section without KEEP is at first place. -## It will be collected then. -## This test checks that lld behavior is equal to gold linker. -## ld.bfd has different behavior, it prevents the section .keep -## from collecting in this case either. +## gold and bfd linkers disagree here. gold collects .keep while +## bfd keeps it. Our current behavior is compatible with bfd although +## we can choose either way. # RUN: echo "SECTIONS { \ # RUN: .nokeep : { *(.keep) } \ # RUN: .keep : { KEEP(*(.keep)) }}" > %t.script # RUN: ld.lld --gc-sections -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | \ -# RUN: FileCheck -check-prefix=KEEP-AT-SECOND %s -# KEEP-AT-SECOND: Sections: -# KEEP-AT-SECOND-NEXT: Idx Name Size Address Type -# KEEP-AT-SECOND-NEXT: 0 00000000 0000000000000000 -# KEEP-AT-SECOND-NEXT: 1 .temp 00000004 0000000000000120 DATA -# KEEP-AT-SECOND-NEXT: 2 .text 00000007 0000000000000124 TEXT DATA -# KEEP-AT-SECOND-NEXT: 3 .symtab 00000048 0000000000000000 -# KEEP-AT-SECOND-NEXT: 4 .shstrtab 00000027 0000000000000000 -# KEEP-AT-SECOND-NEXT: 5 .strtab 0000000d 0000000000000000 +# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED2 %s +# MIXED2: Sections: +# MIXED2-NEXT: Idx Name Size Address Type +# MIXED2-NEXT: 0 00000000 0000000000000000 +# MIXED2-NEXT: 1 .nokeep 00000004 0000000000000120 DATA +# MIXED2-NEXT: 2 .temp 00000004 0000000000000124 DATA +# MIXED2-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA +# MIXED2-NEXT: 4 .symtab 00000060 0000000000000000 +# MIXED2-NEXT: 5 .shstrtab 0000002f 0000000000000000 +# MIXED2-NEXT: 6 .strtab 00000012 0000000000000000 .global _start _start: