[lld] r276398 - [ELF] Support PROVIDE and PROVIDE_HIDDEN inside SECTIONS

Eugene Leviant via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 22 00:38:41 PDT 2016


Author: evgeny777
Date: Fri Jul 22 02:38:40 2016
New Revision: 276398

URL: http://llvm.org/viewvc/llvm-project?rev=276398&view=rev
Log:
[ELF] Support PROVIDE and PROVIDE_HIDDEN inside SECTIONS

Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h
    lld/trunk/test/ELF/linkerscript-locationcounter.s
    lld/trunk/test/ELF/linkerscript-symbols.s

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=276398&r1=276397&r2=276398&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Fri Jul 22 02:38:40 2016
@@ -338,7 +338,7 @@ void LinkerScript<ELFT>::dispatchAssignm
   uint64_t Val = evalExpr(Cmd->Expr, Dot);
   if (Cmd->Name == ".") {
     Dot = Val;
-  } else {
+  } else if (!Cmd->Ignore) {
     auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd->Name));
     D->Value = Val;
   }
@@ -528,10 +528,19 @@ int LinkerScript<ELFT>::compareSections(
 }
 
 template <class ELFT> void LinkerScript<ELFT>::addScriptedSymbols() {
-  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
-    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get()))
-      if (Cmd->Name != "." && Symtab<ELFT>::X->find(Cmd->Name) == nullptr)
-        Symtab<ELFT>::X->addAbsolute(Cmd->Name, STV_DEFAULT);
+  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+    auto *Cmd = dyn_cast<SymbolAssignment>(Base.get());
+    if (!Cmd || Cmd->Name == ".")
+      continue;
+
+    if (Symtab<ELFT>::X->find(Cmd->Name) == nullptr)
+      Symtab<ELFT>::X->addAbsolute(Cmd->Name,
+                                   Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT);
+    else
+      // Symbol already exists in symbol table. If it is provided
+      // then we can't override its value.
+      Cmd->Ignore = Cmd->Provide;
+  }
 }
 
 template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
@@ -592,7 +601,8 @@ private:
   void readOutputSectionDescription(StringRef OutSec);
   std::vector<StringRef> readOutputSectionPhdrs();
   unsigned readPhdrType();
-  void readSymbolAssignment(StringRef Name);
+  void readProvide(bool Hidden);
+  SymbolAssignment *readSymbolAssignment(StringRef Name);
   std::vector<StringRef> readSectionsCommandExpr();
 
   const static StringMap<Handler> Cmd;
@@ -789,7 +799,11 @@ void ScriptParser::readSections() {
       continue;
     }
     next();
-    if (peek() == "=")
+    if (Tok == "PROVIDE")
+      readProvide(false);
+    else if (Tok == "PROVIDE_HIDDEN")
+      readProvide(true);
+    else if (peek() == "=")
       readSymbolAssignment(Tok);
     else
       readOutputSectionDescription(Tok);
@@ -855,19 +869,42 @@ void ScriptParser::readOutputSectionDesc
   }
 }
 
-void ScriptParser::readSymbolAssignment(StringRef Name) {
+void ScriptParser::readProvide(bool Hidden) {
+  expect("(");
+  if (SymbolAssignment *Assignment = readSymbolAssignment(next())) {
+    Assignment->Provide = true;
+    Assignment->Hidden = Hidden;
+  }
+  expect(")");
+  expect(";");
+}
+
+SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
   expect("=");
   std::vector<StringRef> Expr = readSectionsCommandExpr();
-  if (Expr.empty())
+  if (Expr.empty()) {
     error("error in symbol assignment expression");
-  else
+  } else {
     Opt.Commands.push_back(llvm::make_unique<SymbolAssignment>(Name, Expr));
+    return static_cast<SymbolAssignment *>(Opt.Commands.back().get());
+  }
+  return nullptr;
 }
 
+// This function reads balanced expression until semicolon is seen.
 std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
+  int Braces = 0;
   std::vector<StringRef> Expr;
   while (!Error) {
-    StringRef Tok = next();
+    StringRef Tok = peek();
+
+    if (Tok == "(")
+      Braces++;
+    else if (Tok == ")")
+      if (--Braces < 0)
+        break;
+
+    next();
     if (Tok == ";")
       break;
     Expr.push_back(Tok);

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=276398&r1=276397&r2=276398&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Fri Jul 22 02:38:40 2016
@@ -51,6 +51,10 @@ struct SymbolAssignment : BaseCommand {
   static bool classof(const BaseCommand *C);
   StringRef Name;
   std::vector<StringRef> Expr;
+  bool Provide = false;
+  // Hidden and Ignore can be true, only if Provide is true
+  bool Hidden = false;
+  bool Ignore = false;
 };
 
 // Linker scripts allow additional constraints to be put on ouput sections.

Modified: lld/trunk/test/ELF/linkerscript-locationcounter.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-locationcounter.s?rev=276398&r1=276397&r2=276398&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript-locationcounter.s (original)
+++ lld/trunk/test/ELF/linkerscript-locationcounter.s Fri Jul 22 02:38:40 2016
@@ -319,7 +319,7 @@
 # RUN: }" > %t.script
 # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
 # RUN:  FileCheck --check-prefix=BRACKETERR2 %s
-# BRACKETERR2: stray token: )
+# BRACKETERR2: expected, but got *
 
 ## Empty expression.
 # RUN: echo "SECTIONS { \

Modified: lld/trunk/test/ELF/linkerscript-symbols.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-symbols.s?rev=276398&r1=276397&r2=276398&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript-symbols.s (original)
+++ lld/trunk/test/ELF/linkerscript-symbols.s Fri Jul 22 02:38:40 2016
@@ -1,11 +1,43 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 
+# Simple symbol assignment. Should raise conflict in case we 
+# have duplicates in any input section, but currently simply
+# replaces the value.
 # RUN: echo "SECTIONS {.text : {*(.text.*)} text_end = .;}" > %t.script
 # RUN: ld.lld -o %t1 --script %t.script %t
-# RUN: llvm-objdump -t %t1 | FileCheck %s
-# CHECK: 0000000000000121         *ABS*    00000000 text_end
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+# SIMPLE: 0000000000000121         *ABS*    00000000 text_end
+
+# Provide new symbol. The value should be 1, like set in PROVIDE()
+# RUN: echo "SECTIONS { PROVIDE(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE1 %s
+# PROVIDE1: 0000000000000001         *ABS*    00000000 newsym
+
+# Provide new symbol (hidden). The value should be 1
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN1 %s
+# HIDDEN1: 0000000000000001         *ABS*    00000000 .hidden newsym
+
+# Provide existing symbol. The value should be 0, even though we 
+# have value of 1 in PROVIDE()
+# RUN: echo "SECTIONS { PROVIDE(somesym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE2 %s
+# PROVIDE2: 0000000000000000         *ABS*    00000000 somesym
+
+# Provide existing symbol. The value should be 0, even though we 
+# have value of 1 in PROVIDE(). Visibility should not change
+# RUN: echo "SECTIONS { PROVIDE(somesym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN2 %s
+# HIDDEN2: 0000000000000000         *ABS*    00000000 somesym
 
 .global _start
 _start:
  nop
+
+.global somesym
+somesym = 0




More information about the llvm-commits mailing list