[lld] r261616 - [ELF] - Linkerscript KEEP command.
George Rimar via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 22 23:47:54 PST 2016
Author: grimar
Date: Tue Feb 23 01:47:54 2016
New Revision: 261616
URL: http://llvm.org/viewvc/llvm-project?rev=261616&view=rev
Log:
[ELF] - Linkerscript KEEP command.
When link-time garbage collection is in use (-gc-sections), it is
often useful to mark sections that should not be eliminated.
This is accomplished by surrounding an input section's wildcard
entry with KEEP(). Patch implements that command.
Differential revision: http://reviews.llvm.org/D17242
Added:
lld/trunk/test/ELF/linkerscript-sections-keep.s
Modified:
lld/trunk/ELF/LinkerScript.cpp
lld/trunk/ELF/LinkerScript.h
lld/trunk/ELF/MarkLive.cpp
Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=261616&r1=261615&r2=261616&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Tue Feb 23 01:47:54 2016
@@ -31,11 +31,17 @@ using namespace lld::elf2;
LinkerScript *elf2::Script;
template <class ELFT>
-StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {
+SectionRule *LinkerScript::find(InputSectionBase<ELFT> *S) {
for (SectionRule &R : Sections)
if (R.match(S))
- return R.Dest;
- return "";
+ return &R;
+ return nullptr;
+}
+
+template <class ELFT>
+StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {
+ SectionRule *R = find(S);
+ return R ? R->Dest : "";
}
template <class ELFT>
@@ -43,6 +49,11 @@ bool LinkerScript::isDiscarded(InputSect
return getOutputSection(S) == "/DISCARD/";
}
+template <class ELFT> bool LinkerScript::shouldKeep(InputSectionBase<ELFT> *S) {
+ SectionRule *R = find(S);
+ return R && R->Keep;
+}
+
// A compartor to sort output sections. Returns -1 or 1 if both
// A and B are mentioned in linker scripts. Otherwise, returns 0
// to use the default rule which is implemented in Writer.cpp.
@@ -124,6 +135,7 @@ private:
void readSections();
void readOutputSectionDescription();
+ void readSectionPatterns(StringRef OutSec, bool Keep);
StringSaver Saver;
std::vector<StringRef> Tokens;
@@ -374,16 +386,29 @@ void ScriptParser::readSections() {
readOutputSectionDescription();
}
+void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) {
+ expect("(");
+ while (!Error && !skip(")"))
+ Script->Sections.emplace_back(OutSec, next(), Keep);
+}
+
void ScriptParser::readOutputSectionDescription() {
StringRef OutSec = next();
Script->SectionOrder.push_back(OutSec);
expect(":");
expect("{");
while (!Error && !skip("}")) {
- next(); // Skip input file name.
- expect("(");
- while (!Error && !skip(")"))
- Script->Sections.push_back({OutSec, next()});
+ StringRef Tok = next();
+ if (Tok == "*") {
+ readSectionPatterns(OutSec, false);
+ } else if (Tok == "KEEP") {
+ expect("(");
+ next(); // Skip *
+ readSectionPatterns(OutSec, true);
+ expect(")");
+ } else {
+ setError("Unknown command " + Tok);
+ }
}
}
@@ -412,6 +437,11 @@ template bool LinkerScript::isDiscarded(
template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);
+template bool LinkerScript::shouldKeep(InputSectionBase<ELF32LE> *);
+template bool LinkerScript::shouldKeep(InputSectionBase<ELF32BE> *);
+template bool LinkerScript::shouldKeep(InputSectionBase<ELF64LE> *);
+template bool LinkerScript::shouldKeep(InputSectionBase<ELF64BE> *);
+
template bool SectionRule::match(InputSectionBase<ELF32LE> *);
template bool SectionRule::match(InputSectionBase<ELF32BE> *);
template bool SectionRule::match(InputSectionBase<ELF64LE> *);
Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=261616&r1=261615&r2=261616&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Tue Feb 23 01:47:54 2016
@@ -25,13 +25,17 @@ template <class ELFT> class InputSection
// This class represents each rule in SECTIONS command.
class SectionRule {
public:
- SectionRule(StringRef D, StringRef S) : Dest(D), SectionPattern(S) {}
+ SectionRule(StringRef D, StringRef S, bool Keep)
+ : Dest(D), Keep(Keep), SectionPattern(S) {}
// Returns true if S should be in Dest section.
template <class ELFT> bool match(InputSectionBase<ELFT> *S);
StringRef Dest;
+ // KEEP command saves unused sections even if --gc-sections is specified.
+ bool Keep = false;
+
private:
StringRef SectionPattern;
};
@@ -47,9 +51,12 @@ public:
template <class ELFT> StringRef getOutputSection(InputSectionBase<ELFT> *S);
template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
+ template <class ELFT> bool shouldKeep(InputSectionBase<ELFT> *S);
int compareSections(StringRef A, StringRef B);
private:
+ template <class ELFT> SectionRule *find(InputSectionBase<ELFT> *S);
+
// SECTIONS commands.
std::vector<SectionRule> Sections;
Modified: lld/trunk/ELF/MarkLive.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/MarkLive.cpp?rev=261616&r1=261615&r2=261616&view=diff
==============================================================================
--- lld/trunk/ELF/MarkLive.cpp (original)
+++ lld/trunk/ELF/MarkLive.cpp Tue Feb 23 01:47:54 2016
@@ -21,6 +21,7 @@
//===----------------------------------------------------------------------===//
#include "InputSection.h"
+#include "LinkerScript.h"
#include "OutputSections.h"
#include "SymbolTable.h"
#include "Symbols.h"
@@ -113,11 +114,13 @@ template <class ELFT> void elf2::markLiv
}
}
- // Preserve special sections.
+ // Preserve special sections and those which are specified in linker
+ // script KEEP command.
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab->getObjectFiles())
for (InputSectionBase<ELFT> *Sec : F->getSections())
- if (Sec && Sec != &InputSection<ELFT>::Discarded && isReserved(Sec))
- Enqueue(Sec);
+ if (Sec && Sec != &InputSection<ELFT>::Discarded)
+ if (isReserved(Sec) || Script->shouldKeep<ELFT>(Sec))
+ Enqueue(Sec);
// Mark all reachable sections.
while (!Q.empty())
Added: lld/trunk/test/ELF/linkerscript-sections-keep.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-sections-keep.s?rev=261616&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript-sections-keep.s (added)
+++ lld/trunk/test/ELF/linkerscript-sections-keep.s Tue Feb 23 01:47:54 2016
@@ -0,0 +1,82 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## First check that section "keep" is garbage collected without using KEEP
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .keep : { *(.keep) } \
+# RUN: .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN: FileCheck -check-prefix=SECGC %s
+# SECGC: Sections:
+# SECGC-NEXT: Idx Name Size Address Type
+# SECGC-NEXT: 0 00000000 0000000000000000
+# SECGC-NEXT: 1 .text 00000007 0000000000011000 TEXT DATA
+# SECGC-NEXT: 2 .temp 00000004 0000000000012000 DATA
+
+## Now apply KEEP command to preserve the section.
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .keep : { KEEP(*(.keep)) } \
+# RUN: .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN: FileCheck -check-prefix=SECNOGC %s
+# SECNOGC: Sections:
+# SECNOGC-NEXT: Idx Name Size Address Type
+# SECNOGC-NEXT: 0 00000000 0000000000000000
+# SECNOGC-NEXT: 1 .text 00000007 0000000000011000 TEXT DATA
+# SECNOGC-NEXT: 2 .keep 00000004 0000000000012000 DATA
+# SECNOGC-NEXT: 3 .temp 00000004 0000000000012004 DATA
+
+## A section name matches two entries in the SECTIONS directive. The
+## first one doesn't have KEEP, the second one does. If section that have
+## KEEP is the first in order then section is NOT collected.
+# RUN: echo "SECTIONS { \
+# 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 0000000000010120 DATA
+# KEEP-AT-FIRST-NEXT: 2 .temp 00000004 0000000000010124 DATA
+# KEEP-AT-FIRST-NEXT: 3 .text 00000007 0000000000011000 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
+
+## 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.
+# 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 0000000000010120 DATA
+# KEEP-AT-SECOND-NEXT: 2 .text 00000007 0000000000011000 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
+
+.global _start
+_start:
+ mov temp, %eax
+
+.section .keep, "a"
+keep:
+ .long 1
+
+.section .temp, "a"
+temp:
+ .long 2
More information about the llvm-commits
mailing list