[lld] r266227 - ELF: Implement --dynamic-list

Adhemerval Zanella via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 13 11:51:12 PDT 2016


Author: azanella
Date: Wed Apr 13 13:51:11 2016
New Revision: 266227

URL: http://llvm.org/viewvc/llvm-project?rev=266227&view=rev
Log:
ELF: Implement --dynamic-list

This patch implements the --dynamic-list option, which adds a list of
global symbol that either should not be bounded by default definition
when creating shared libraries, or add in dynamic symbol table in the
case of creating executables.

The patch modifies the ScriptParserBase class to use a list of Token
instead of StringRef, which contains information if the token is a
quoted or unquoted strings. It is used to use a faster search for
exact match symbol name.

The input file follow a similar format of linker script with some
simplifications (it does not have scope or node names). It leads
to a simplified parser define in DynamicList.{cpp,h}.

Different from ld/gold neither glob pattern nor mangled names
(extern 'C++') are currently supported.

Added:
    lld/trunk/ELF/DynamicList.cpp
    lld/trunk/ELF/DynamicList.h
    lld/trunk/test/ELF/dynamic-list.s
    lld/trunk/test/ELF/invalid-dynamic-list.test
Modified:
    lld/trunk/ELF/CMakeLists.txt
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/Driver.h
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h

Modified: lld/trunk/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/CMakeLists.txt?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/CMakeLists.txt (original)
+++ lld/trunk/ELF/CMakeLists.txt Wed Apr 13 13:51:11 2016
@@ -5,6 +5,7 @@ add_public_tablegen_target(ELFOptionsTab
 add_lld_library(lldELF
   Driver.cpp
   DriverUtils.cpp
+  DynamicList.cpp
   Error.cpp
   ICF.cpp
   InputFiles.cpp

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Wed Apr 13 13:51:11 2016
@@ -48,6 +48,7 @@ struct Configuration {
   llvm::StringRef SoName;
   llvm::StringRef Sysroot;
   std::string RPath;
+  std::vector<llvm::StringRef> DynamicList;
   std::vector<llvm::StringRef> SearchPaths;
   std::vector<llvm::StringRef> Undefined;
   bool AllowMultipleDefinition;

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Wed Apr 13 13:51:11 2016
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Driver.h"
+#include "DynamicList.h"
 #include "Config.h"
 #include "Error.h"
 #include "ICF.h"
@@ -100,14 +101,10 @@ void LinkerDriver::addFile(StringRef Pat
   using namespace llvm::sys::fs;
   if (Config->Verbose)
     llvm::outs() << Path << "\n";
-  auto MBOrErr = MemoryBuffer::getFile(Path);
-  if (!MBOrErr) {
-    error(MBOrErr, "cannot open " + Path);
+  Optional<MemoryBufferRef> Buffer = readFile(Path);
+  if (!Buffer.hasValue())
     return;
-  }
-  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
-  MemoryBufferRef MBRef = MB->getMemBufferRef();
-  OwningMBs.push_back(std::move(MB)); // take MB ownership
+  MemoryBufferRef MBRef = *Buffer;
 
   switch (identify_magic(MBRef.getBuffer())) {
   case file_magic::unknown:
@@ -136,6 +133,23 @@ void LinkerDriver::addFile(StringRef Pat
   }
 }
 
+Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {
+  auto MBOrErr = MemoryBuffer::getFile(Path);
+  if (std::error_code EC = MBOrErr.getError()) {
+    error(MBOrErr, "cannot open " + Path);
+    return None;
+  }
+  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+  MemoryBufferRef MBRef = MB->getMemBufferRef();
+  OwningMBs.push_back(std::move(MB)); // take MB ownership
+  return MBRef;
+}
+
+void LinkerDriver::readDynamicList(StringRef Path) {
+  if (Optional<MemoryBufferRef> Buffer = readFile(Path))
+    parseDynamicList(*Buffer);
+}
+
 // Add a given library by searching it from input search paths.
 void LinkerDriver::addLibrary(StringRef Name) {
   std::string Path = searchLibrary(Name);
@@ -351,6 +365,9 @@ void LinkerDriver::readConfigs(opt::Inpu
 
   for (auto *Arg : Args.filtered(OPT_undefined))
     Config->Undefined.push_back(Arg->getValue());
+
+  if (Args.hasArg(OPT_dynamic_list))
+    readDynamicList(getString(Args, OPT_dynamic_list));
 }
 
 void LinkerDriver::createFiles(opt::InputArgList &Args) {
@@ -437,6 +454,7 @@ template <class ELFT> void LinkerDriver:
 
   // Write the result to the file.
   Symtab.scanShlibUndefined();
+  Symtab.scanDynamicList();
   if (Config->GcSections)
     markLive<ELFT>(&Symtab);
   if (Config->ICF)

Modified: lld/trunk/ELF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.h (original)
+++ lld/trunk/ELF/Driver.h Wed Apr 13 13:51:11 2016
@@ -12,6 +12,7 @@
 
 #include "SymbolTable.h"
 #include "lld/Core/LLVM.h"
+#include "llvm/ADT/Optional.h" 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/raw_ostream.h"
@@ -29,7 +30,9 @@ public:
 
 private:
   std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);
+  llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
   void readConfigs(llvm::opt::InputArgList &Args);
+  void readDynamicList(StringRef Path);
   void createFiles(llvm::opt::InputArgList &Args);
   template <class ELFT> void link(llvm::opt::InputArgList &Args);
 

Added: lld/trunk/ELF/DynamicList.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/DynamicList.cpp?rev=266227&view=auto
==============================================================================
--- lld/trunk/ELF/DynamicList.cpp (added)
+++ lld/trunk/ELF/DynamicList.cpp Wed Apr 13 13:51:11 2016
@@ -0,0 +1,64 @@
+//===- LinkerScript.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+// It does not construct an AST but consume linker script directives directly.
+// Results are written to Driver or Config object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicList.h"
+#include "Config.h"
+#include "ScriptParser.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Parse the --dynamic-list argument.  A dynamic list is in the form
+//
+//  { symbol1; symbol2; [...]; symbolN };
+//
+// Multiple groups can be defined in the same file and they are merged
+// in only one definition.
+
+class DynamicListParser final : public ScriptParserBase {
+public:
+  DynamicListParser(StringRef S) : ScriptParserBase(S) {}
+
+  void run() override;
+
+private:
+  void readGroup();
+};
+
+// Parse the default group definition using C language symbol name.
+void DynamicListParser::readGroup() {
+  expect("{");
+  while (!Error) {
+    Config->DynamicList.push_back(next());
+    expect(";");
+    if (peek() == "}") {
+      next();
+      break;
+    }
+  }
+  expect(";");
+}
+
+void DynamicListParser::run() {
+  while (!atEOF())
+    readGroup();
+}
+
+void elf::parseDynamicList(MemoryBufferRef MB) {
+  DynamicListParser(MB.getBuffer()).run();
+}

Added: lld/trunk/ELF/DynamicList.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/DynamicList.h?rev=266227&view=auto
==============================================================================
--- lld/trunk/ELF/DynamicList.h (added)
+++ lld/trunk/ELF/DynamicList.h Wed Apr 13 13:51:11 2016
@@ -0,0 +1,24 @@
+//===- DynamicList.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_DYNAMIC_LIST_H
+#define LLD_ELF_DYNAMIC_LIST_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+void parseDynamicList(MemoryBufferRef MB);
+
+} // namespace elf
+} // namespace lld
+
+#endif

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Wed Apr 13 13:51:11 2016
@@ -44,6 +44,9 @@ def discard_none : Flag<["-"], "discard-
 def dynamic_linker : Separate<["--", "-"], "dynamic-linker">,
   HelpText<"Which dynamic linker to use">;
 
+def dynamic_list : Separate<["--", "-"], "dynamic-list">,
+  HelpText<"Read a list of dynamic symbols">;
+
 def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
   HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
 
@@ -175,6 +178,7 @@ def alias_Bstatic_static: Flag<["-"], "s
 def alias_L__library_path : Joined<["--"], "library-path=">, Alias<L>;
 def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
 def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
+def alias_dynamic_list: Joined<["--", "-"], "dynamic-list=">, Alias<dynamic_list>;
 def alias_entry_e : JoinedOrSeparate<["-"], "e">, Alias<entry>;
 def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
 def alias_fini_fini : Joined<["-"], "fini=">, Alias<fini>;

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Wed Apr 13 13:51:11 2016
@@ -339,6 +339,14 @@ template <class ELFT> void SymbolTable<E
           Sym->MustBeInDynSym = true;
 }
 
+// This function process the dynamic list option by marking all the symbols
+// to be exported in the dynamic table.
+template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
+  for (StringRef S : Config->DynamicList)
+    if (SymbolBody *B = find(S))
+      B->MustBeInDynSym = true;
+}
+
 template class elf::SymbolTable<ELF32LE>;
 template class elf::SymbolTable<ELF32BE>;
 template class elf::SymbolTable<ELF64LE>;

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=266227&r1=266226&r2=266227&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Wed Apr 13 13:51:11 2016
@@ -60,6 +60,7 @@ public:
                                    uint8_t Visibility = llvm::ELF::STV_HIDDEN);
 
   void scanShlibUndefined();
+  void scanDynamicList();
   SymbolBody *find(StringRef Name);
   void wrap(StringRef Name);
   InputFile *findFile(SymbolBody *B);

Added: lld/trunk/test/ELF/dynamic-list.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/dynamic-list.s?rev=266227&view=auto
==============================================================================
--- lld/trunk/test/ELF/dynamic-list.s (added)
+++ lld/trunk/test/ELF/dynamic-list.s Wed Apr 13 13:51:11 2016
@@ -0,0 +1,104 @@
+## There is some bad quoting interaction between lit's internal shell, which is
+## implemented in Python, and the Cygwin implementations of the Unix utilities.
+## Avoid running these tests on Windows for now by requiring a real shell.
+
+# REQUIRES: shell
+
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check exporting only one symbol.
+# RUN: echo "{ foo1; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+## And now using quoted strings (the output is the same since it does
+## use any wildcard character).
+# RUN: echo "{ \"foo1\"; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo1@ (1)
+# CHECK-NEXT:     Value: 0x11000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text (0x4)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ] 
+
+
+## Now export all the foo1, foo2, and foo31 symbols
+# RUN: echo "{ foo1; foo2; foo31; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2:      DynamicSymbols [
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: @ (0)
+# CHECK2-NEXT:     Value: 0x0
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Local
+# CHECK2-NEXT:     Type: None
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: Undefined
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo1@ (1)
+# CHECK2-NEXT:     Value: 0x11000
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo2@ (6)
+# CHECK2-NEXT:     Value: 0x11001
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo31@ (11)
+# CHECK2-NEXT:     Value: 0x11002
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT: ] 
+
+.globl foo1
+foo1:
+  ret
+
+.globl foo2
+foo2:
+  ret
+
+.globl foo31
+foo31:
+  ret
+
+.globl _start
+_start:
+  retq

Added: lld/trunk/test/ELF/invalid-dynamic-list.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/invalid-dynamic-list.test?rev=266227&view=auto
==============================================================================
--- lld/trunk/test/ELF/invalid-dynamic-list.test (added)
+++ lld/trunk/test/ELF/invalid-dynamic-list.test Wed Apr 13 13:51:11 2016
@@ -0,0 +1,37 @@
+## Different "echo" commands on Windows interpret quoted strings and
+## wildcards in similar but different way (On Windows, ARGV tokenization
+## and wildcard expansion are not done by the shell but by each command.)
+## Because of that reason, this test fails on some Windows environment.
+## We can't write quoted strings that are interpreted the same way
+## by all echo commands. So, we don't want to run this on Windows.
+
+# REQUIRES: shell
+
+# RUN: mkdir -p %t.dir
+
+# RUN: echo foobar > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: line 1: { expected, but got foobar
+
+# RUN: echo "{ foobar;" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: line 1: unexpected EOF
+
+## Missing ';' before '}'
+# RUN: echo "{ foobar }" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: line 1: ; expected, but got }
+
+## Missing final ';'
+# RUN: echo "{ foobar; }" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: line 1: unexpected EOF
+
+## Missing \" in foobar definition
+# RUN echo "{ \"foobar; };" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: line 1: unexpected EOF
+
+# RUN: echo "{ extern \"BOGUS\" { test }; };" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: line 1: ; expected, but got BOGUS




More information about the llvm-commits mailing list