[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