[lld] r277042 - [ELF] - Linkerscript: implemented filename specification.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 28 14:51:30 PDT 2016


Author: grimar
Date: Thu Jul 28 16:51:30 2016
New Revision: 277042

URL: http://llvm.org/viewvc/llvm-project?rev=277042&view=rev
Log:
[ELF] - Linkerscript: implemented filename specification.

Scripts can contain something like:
KEEP (*crtbegin.o(.ctors))

What means that "*crtbegin.o" is a wildcard of file to take the sections from.
This is some kind of opposite to EXCLUDE_FILE and used in FreeBSD script:
https://svnweb.freebsd.org/base/head/sys/conf/ldscript.amd64?revision=284870&view=markup#l122

Patch implements this.

Differential revision: https://reviews.llvm.org/D22852

Added:
    lld/trunk/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s
    lld/trunk/test/ELF/linkerscript/linkerscript-filename-spec.s
Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=277042&r1=277041&r2=277042&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Thu Jul 28 16:51:30 2016
@@ -92,20 +92,27 @@ LinkerScript<ELFT>::getSectionMap() {
   return Ret;
 }
 
+static bool fileMatches(const InputSectionDescription *Desc,
+                        StringRef Filename) {
+  if (!globMatch(Desc->FilePattern, Filename))
+    return false;
+  return Desc->ExcludedFiles.empty() || !match(Desc->ExcludedFiles, Filename);
+}
+
 // Returns input sections filtered by given glob patterns.
 template <class ELFT>
 std::vector<InputSectionBase<ELFT> *>
 LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) {
-  ArrayRef<StringRef> Patterns = I->Patterns;
-  ArrayRef<StringRef> ExcludedFiles = I->ExcludedFiles;
+  ArrayRef<StringRef> Patterns = I->SectionPatterns;
   std::vector<InputSectionBase<ELFT> *> Ret;
   for (const std::unique_ptr<ObjectFile<ELFT>> &F :
-       Symtab<ELFT>::X->getObjectFiles())
-    for (InputSectionBase<ELFT> *S : F->getSections())
-      if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName()))
-        if (ExcludedFiles.empty() ||
-            !match(ExcludedFiles, sys::path::filename(F->getName())))
+       Symtab<ELFT>::X->getObjectFiles()) {
+    if (fileMatches(I, sys::path::filename(F->getName())))
+      for (InputSectionBase<ELFT> *S : F->getSections())
+        if (!isDiscarded(S) && !S->OutSec &&
+            match(Patterns, S->getSectionName()))
           Ret.push_back(S);
+  }
 
   if ((llvm::find(Patterns, "COMMON") != Patterns.end()))
     Ret.push_back(CommonInputSection<ELFT>::X);
@@ -428,9 +435,7 @@ private:
   void readAsNeeded();
   void readEntry();
   void readExtern();
-  std::unique_ptr<InputSectionDescription> readFilePattern();
   void readGroup();
-  void readKeep(OutputSectionCommand *Cmd);
   void readInclude();
   void readNothing() {}
   void readOutput();
@@ -443,6 +448,8 @@ private:
   SymbolAssignment *readAssignment(StringRef Name);
   void readOutputSectionDescription(StringRef OutSec);
   std::vector<StringRef> readOutputSectionPhdrs();
+  std::unique_ptr<InputSectionDescription> readInputSectionDescription();
+  void readInputSectionRules(InputSectionDescription *InCmd, bool Keep);
   unsigned readPhdrType();
   void readProvide(bool Hidden);
   void readAlign(OutputSectionCommand *Cmd);
@@ -672,32 +679,38 @@ static int precedence(StringRef Op) {
       .Default(-1);
 }
 
-std::unique_ptr<InputSectionDescription> ScriptParser::readFilePattern() {
-  expect("*");
+void ScriptParser::readInputSectionRules(InputSectionDescription *InCmd, bool Keep) {
+  InCmd->FilePattern = next();
   expect("(");
 
-  auto InCmd = llvm::make_unique<InputSectionDescription>();
-
   if (skip("EXCLUDE_FILE")) {
     expect("(");
     while (!Error && !skip(")"))
       InCmd->ExcludedFiles.push_back(next());
-    InCmd->Patterns.push_back(next());
+  }
+
+  while (!Error && !skip(")")) {
+    if (Keep)
+      Opt.KeptSections.push_back(peek());
+    InCmd->SectionPatterns.push_back(next());
+  }
+}
+
+std::unique_ptr<InputSectionDescription>
+ScriptParser::readInputSectionDescription() {
+  auto InCmd = std::make_unique<InputSectionDescription>();
+
+  // Input section wildcard can be surrounded by KEEP.
+  // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+  if (skip("KEEP")) {
+    expect("(");
+    readInputSectionRules(InCmd.get(), true);
     expect(")");
   } else {
-    while (!Error && !skip(")"))
-      InCmd->Patterns.push_back(next());
+    readInputSectionRules(InCmd.get(), false);
   }
-  return InCmd;
-}
 
-void ScriptParser::readKeep(OutputSectionCommand *Cmd) {
-  expect("(");
-  std::unique_ptr<InputSectionDescription> InCmd = readFilePattern();
-  Opt.KeptSections.insert(Opt.KeptSections.end(), InCmd->Patterns.begin(),
-                          InCmd->Patterns.end());
-  Cmd->Commands.push_back(std::move(InCmd));
-  expect(")");
+  return InCmd;
 }
 
 void ScriptParser::readAlign(OutputSectionCommand *Cmd) {
@@ -734,16 +747,13 @@ void ScriptParser::readOutputSectionDesc
   expect("{");
 
   while (!Error && !skip("}")) {
+    if ((!peek().empty() && peek()[0] == '*') || peek() == "KEEP") {
+      Cmd->Commands.push_back(readInputSectionDescription());
+      continue;
+    }
+
     StringRef Tok = next();
-    if (Tok == "*") {
-      auto *InCmd = new InputSectionDescription();
-      Cmd->Commands.emplace_back(InCmd);
-      expect("(");
-      while (!Error && !skip(")"))
-        InCmd->Patterns.push_back(next());
-    } else if (Tok == "KEEP") {
-      readKeep(Cmd);
-    } else if (Tok == "PROVIDE") {
+    if (Tok == "PROVIDE") {
       readProvide(false);
     } else if (Tok == "PROVIDE_HIDDEN") {
       readProvide(true);

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=277042&r1=277041&r2=277042&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Thu Jul 28 16:51:30 2016
@@ -84,8 +84,9 @@ struct OutputSectionCommand : BaseComman
 struct InputSectionDescription : BaseCommand {
   InputSectionDescription() : BaseCommand(InputSectionKind) {}
   static bool classof(const BaseCommand *C);
+  StringRef FilePattern;
   std::vector<StringRef> ExcludedFiles;
-  std::vector<StringRef> Patterns;
+  std::vector<StringRef> SectionPatterns;
 };
 
 struct PhdrsCommand {

Added: lld/trunk/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s?rev=277042&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s (added)
+++ lld/trunk/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s Thu Jul 28 16:51:30 2016
@@ -0,0 +1,2 @@
+.section .foo,"a"
+  .quad 0x11

Added: lld/trunk/test/ELF/linkerscript/linkerscript-filename-spec.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/linkerscript-filename-spec.s?rev=277042&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/linkerscript-filename-spec.s (added)
+++ lld/trunk/test/ELF/linkerscript/linkerscript-filename-spec.s Thu Jul 28 16:51:30 2016
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/linkerscript-filename-spec.s -o %tsecond.o
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   KEEP(*first.o(.foo)) \
+# RUN:   KEEP(*second.o(.foo)) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s
+# FIRSTSECOND:      Contents of section .foo:
+# FIRSTSECOND-NEXT:   0120 01000000 00000000 11000000 00000000
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   KEEP(*second.o(.foo)) \
+# RUN:   KEEP(*first.o(.foo)) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s
+# SECONDFIRST:      Contents of section .foo:
+# SECONDFIRST-NEXT:   0120 11000000 00000000 01000000 00000000
+
+## Now the same tests but without KEEP. Checking that file name inside
+## KEEP is parsed fine.
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   *first.o(.foo) \
+# RUN:   *second.o(.foo) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   *second.o(.foo) \
+# RUN:   *first.o(.foo) } }" > %t4.script
+# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 1




More information about the llvm-commits mailing list