Change the implementation of --dynamic-list to use linker script parsing.
authorRafael Espindola <rafael.espindola@gmail.com>
Thu, 8 Dec 2016 17:54:26 +0000 (17:54 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Thu, 8 Dec 2016 17:54:26 +0000 (17:54 +0000)
The feature is documented as
-----------------------------
The format of the dynamic list is the same as the version node
without scope and node name.  See *note VERSION:: for more
information.
--------------------------------

And indeed qt uses a dynamic list with an 'extern "C++"' in it. With
this patch we support that

The change to gc-sections-shared makes us match bfd. Just because we
kept bar doesn't mean it has to be in the dynamic symbol table.

The changes to invalid-dynamic-list.test and reproduce.s are because
of the new parser.

The changes to version-script.s are the only case where we change
behavior with regards to bfd, but I would like to see a mix of
--version-script and --dynamic-list used in the wild before
complicating the code.

llvm-svn: 289082

12 files changed:
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/Driver.h
lld/ELF/DriverUtils.cpp
lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/ELF/SymbolTable.cpp
lld/ELF/SymbolTable.h
lld/test/ELF/gc-sections-shared.s
lld/test/ELF/invalid-dynamic-list.test
lld/test/ELF/reproduce.s
lld/test/ELF/version-script.s

index 9d7be7d..890e33a 100644 (file)
@@ -87,7 +87,6 @@ struct Configuration {
   std::string RPath;
   std::vector<VersionDefinition> VersionDefinitions;
   std::vector<llvm::StringRef> AuxiliaryList;
-  std::vector<llvm::StringRef> DynamicList;
   std::vector<llvm::StringRef> SearchPaths;
   std::vector<llvm::StringRef> Undefined;
   std::vector<SymbolVersion> VersionScriptGlobals;
index 0bfc093..2095e73 100644 (file)
@@ -627,14 +627,24 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
 
   if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
     if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
-      parseDynamicList(*Buffer);
+      readDynamicList(*Buffer);
 
   if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
     if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
       parseSymbolOrderingList(*Buffer);
 
   for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
-    Config->DynamicList.push_back(Arg->getValue());
+    Config->VersionScriptGlobals.push_back(
+        {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+
+  // Dynamic lists are a simplified linker script that doesn't need the
+  // "global:" and implicitly ends with a "local:*". Set the variables needed to
+  // simulate that.
+  if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) {
+    Config->ExportDynamic = true;
+    if (!Config->Shared)
+      Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+  }
 
   if (auto *Arg = Args.getLastArg(OPT_version_script))
     if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
@@ -793,7 +803,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
 
   Symtab.scanUndefinedFlags();
   Symtab.scanShlibUndefined();
-  Symtab.scanDynamicList();
   Symtab.scanVersionScript();
 
   Symtab.addCombinedLTOObject();
index 74d465e..a3a3a84 100644 (file)
@@ -69,7 +69,6 @@ enum {
 
 void printHelp(const char *Argv0);
 std::vector<uint8_t> parseHexstring(StringRef S);
-void parseDynamicList(MemoryBufferRef MB);
 
 std::string createResponseFile(const llvm::opt::InputArgList &Args);
 
index d56dfba..6a270a6 100644 (file)
@@ -90,32 +90,6 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
   return Args;
 }
 
-// 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
-// into a single group.
-void elf::parseDynamicList(MemoryBufferRef MB) {
-  class Parser : public ScriptParserBase {
-  public:
-    Parser(MemoryBufferRef MB) : ScriptParserBase(MB) {}
-
-    void run() {
-      while (!atEOF()) {
-        expect("{");
-        while (!Error && !consume("}")) {
-          Config->DynamicList.push_back(unquote(next()));
-          expect(";");
-        }
-        expect(";");
-      }
-    }
-  };
-
-  Parser(MB).run();
-}
-
 void elf::printHelp(const char *Argv0) {
   ELFOptTable Table;
   Table.PrintHelp(outs(), Argv0, "lld", false);
index f62cdce..50ce955 100644 (file)
@@ -987,6 +987,7 @@ public:
 
   void readLinkerScript();
   void readVersionScript();
+  void readDynamicList();
 
 private:
   void addFile(StringRef Path);
@@ -1040,6 +1041,13 @@ private:
   std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
 };
 
+void ScriptParser::readDynamicList() {
+  expect("{");
+  readAnonymousDeclaration();
+  if (!atEOF())
+    setError("EOF expected, but got " + next());
+}
+
 void ScriptParser::readVersionScript() {
   readVersionScriptCommand();
   if (!atEOF())
@@ -1932,7 +1940,7 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
   StringRef Tok = next();
   bool IsCXX = Tok == "\"C++\"";
   if (!IsCXX && Tok != "\"C\"")
-    setError("Unknown Language");
+    setError("Unknown language");
   expect("{");
 
   std::vector<SymbolVersion> Ret;
@@ -1956,6 +1964,10 @@ void elf::readVersionScript(MemoryBufferRef MB) {
   ScriptParser(MB).readVersionScript();
 }
 
+void elf::readDynamicList(MemoryBufferRef MB) {
+  ScriptParser(MB).readDynamicList();
+}
+
 template class elf::LinkerScript<ELF32LE>;
 template class elf::LinkerScript<ELF32BE>;
 template class elf::LinkerScript<ELF64LE>;
index 3bcfc57..f6428e1 100644 (file)
@@ -66,6 +66,8 @@ void readLinkerScript(MemoryBufferRef MB);
 // Parses a version script.
 void readVersionScript(MemoryBufferRef MB);
 
+void readDynamicList(MemoryBufferRef MB);
+
 // This enum is used to implement linker script SECTIONS command.
 // https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
 enum SectionsCommandKind {
index 4fb611d..078fbb3 100644 (file)
@@ -535,13 +535,6 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
           Sym->symbol()->ExportDynamic = true;
 }
 
-// This function processes --export-dynamic-symbol and --dynamic-list.
-template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
-  for (StringRef S : Config->DynamicList)
-    if (SymbolBody *B = find(S))
-      B->symbol()->ExportDynamic = true;
-}
-
 // Initialize DemangledSyms with a map from demangled symbols to symbol
 // objects. Used to handle "extern C++" directive in version scripts.
 //
index 0e1b62f..cd9bef3 100644 (file)
@@ -81,7 +81,6 @@ public:
 
   void scanUndefinedFlags();
   void scanShlibUndefined();
-  void scanDynamicList();
   void scanVersionScript();
 
   SymbolBody *find(StringRef Name);
index f1ac9cd..a88f2b4 100644 (file)
 # CHECK-NEXT:     Section: Undefined (0x0)
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Symbol {
-# CHECK-NEXT:     Name: bar
-# CHECK-NEXT:     Value:
-# CHECK-NEXT:     Size:
-# CHECK-NEXT:     Binding: Global
-# CHECK-NEXT:     Type:
-# CHECK-NEXT:     Other:
-# CHECK-NEXT:     Section: .text
-# CHECK-NEXT:   }
-# CHECK-NEXT:   Symbol {
 # CHECK-NEXT:     Name: bar2
 # CHECK-NEXT:     Value:
 # CHECK-NEXT:     Size:
index 5c478a9..f560cee 100644 (file)
@@ -34,4 +34,4 @@
 
 # RUN: echo "{ extern \"BOGUS\" { test }; };" > %t1
 # RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR6 %s
-# ERR6: {{.*}}:1: ; expected, but got "BOGUS"
+# ERR6: {{.*}}:1: Unknown language
index 9166fb4..a29971b 100644 (file)
@@ -30,7 +30,7 @@
 # RUN: diff %t.dir/build2/foo.o repro/%:t.dir/build2/foo.o
 
 # RUN: echo "{ local: *; };" >  ver
-# RUN: echo > dyn
+# RUN: echo "{};" > dyn
 # RUN: echo > file
 # RUN: echo > file2
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o 'foo bar'
index 2825f0f..7453981 100644 (file)
 # RUN: ld.lld --version-script %t3.script -shared %t.o %t2.so -o %t3.so
 # RUN: llvm-readobj -dyn-symbols %t3.so | FileCheck --check-prefix=DSO2 %s
 
-# --version-script filters --dynamic-list.
-# RUN: echo "{ foo1; foo2; };" > %t.list
-# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t
-# RUN: llvm-readobj -dyn-symbols %t | FileCheck --check-prefix=EXE %s
-
 # RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t4.script
 # RUN: echo "VERSION_2.0 { global: foo3; local: *; };" >> %t4.script
 # RUN: ld.lld --version-script %t4.script -shared %t.o %t2.so -o %t4.so
@@ -42,6 +37,7 @@
 # RUN:   FileCheck -check-prefix=WARN2 %s
 # WARN2: duplicate symbol 'foo1' in version script
 
+# RUN: echo "{ foo1; foo2; };" > %t.list
 # RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2
 # RUN: llvm-readobj %t2 > /dev/null
 
 # DSO2-NEXT:   }
 # DSO2-NEXT: ]
 
-# EXE:      DynamicSymbols [
-# EXE-NEXT:   Symbol {
-# EXE-NEXT:     Name: @
-# EXE-NEXT:     Value: 0x0
-# EXE-NEXT:     Size: 0
-# EXE-NEXT:     Binding: Local (0x0)
-# EXE-NEXT:     Type: None (0x0)
-# EXE-NEXT:     Other: 0
-# EXE-NEXT:     Section: Undefined (0x0)
-# EXE-NEXT:   }
-# EXE-NEXT:   Symbol {
-# EXE-NEXT:     Name: bar@
-# EXE-NEXT:     Value: 0x0
-# EXE-NEXT:     Size: 0
-# EXE-NEXT:     Binding: Global (0x1)
-# EXE-NEXT:     Type: Function (0x2)
-# EXE-NEXT:     Other: 0
-# EXE-NEXT:     Section: Undefined (0x0)
-# EXE-NEXT:   }
-# EXE-NEXT:   Symbol {
-# EXE-NEXT:     Name: foo1@
-# EXE-NEXT:     Value: 0x201000
-# EXE-NEXT:     Size: 0
-# EXE-NEXT:     Binding: Global (0x1)
-# EXE-NEXT:     Type: None (0x0)
-# EXE-NEXT:     Other: 0
-# EXE-NEXT:     Section: .text
-# EXE-NEXT:   }
-# EXE-NEXT: ]
-
 # VERDSO:      DynamicSymbols [
 # VERDSO-NEXT:   Symbol {
 # VERDSO-NEXT:     Name: @