[lld] r228060 - ELF: Support INPUT linker script directive

Rui Ueyama ruiu at google.com
Tue Feb 3 15:00:20 PST 2015


Author: ruiu
Date: Tue Feb  3 17:00:19 2015
New Revision: 228060

URL: http://llvm.org/viewvc/llvm-project?rev=228060&view=rev
Log:
ELF: Support INPUT linker script directive

INPUT directive is a variant of GROUP in the sense that that specifies
a list of input files. The only difference is whether the entire file
list is wrapped with a --start-group/--end-group or not.

http://reviews.llvm.org/D7390

Modified:
    lld/trunk/include/lld/ReaderWriter/LinkerScript.h
    lld/trunk/lib/Driver/GnuLdDriver.cpp
    lld/trunk/lib/ReaderWriter/LinkerScript.cpp
    lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp

Modified: lld/trunk/include/lld/ReaderWriter/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (original)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Tue Feb  3 17:00:19 2015
@@ -74,6 +74,7 @@ public:
     kw_exclude_file,
     kw_group,
     kw_hidden,
+    kw_input,
     kw_keep,
     kw_provide,
     kw_provide_hidden,
@@ -150,6 +151,7 @@ public:
   enum class Kind {
     Entry,
     Group,
+    Input,
     InputSectionsCmd,
     Output,
     OutputArch,
@@ -250,16 +252,18 @@ struct Path {
       : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {}
 };
 
-class Group : public Command {
+template<Command::Kind K>
+class PathList : public Command {
 public:
-  template <class RangeT> explicit Group(RangeT range) : Command(Kind::Group) {
+  template <class RangeT> PathList(StringRef name, RangeT range)
+      : Command(K), _name(name) {
     std::copy(std::begin(range), std::end(range), std::back_inserter(_paths));
   }
 
-  static bool classof(const Command *c) { return c->getKind() == Kind::Group; }
+  static bool classof(const Command *c) { return c->getKind() == K; }
 
   void dump(raw_ostream &os) const override {
-    os << "GROUP(";
+    os << _name << "(";
     bool first = true;
     for (const Path &path : getPaths()) {
       if (!first)
@@ -279,9 +283,22 @@ public:
   const std::vector<Path> &getPaths() const { return _paths; }
 
 private:
+  StringRef _name;
   std::vector<Path> _paths;
 };
 
+class Group : public PathList<Command::Kind::Group> {
+public:
+  template <class RangeT> Group(RangeT range)
+      : PathList("GROUP", std::move(range)) {}
+};
+
+class Input : public PathList<Command::Kind::Input> {
+public:
+  template <class RangeT> Input(RangeT range)
+      : PathList("INPUT", std::move(range)) {}
+};
+
 class Entry : public Command {
 public:
   explicit Entry(StringRef entryName)
@@ -886,7 +903,7 @@ private:
   ///
   OutputArch *parseOutputArch();
 
-  /// Parse the GROUP linker script command.
+  /// Parse the INPUT or GROUP linker script command.
   /// Example:
   ///
   /// GROUP ( /lib/x86_64-linux-gnu/libc.so.6
@@ -894,7 +911,7 @@ private:
   ///         AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 )
   ///         -lm -l:libgcc.a )
   ///
-  Group *parseGroup();
+  template<class T> T *parsePathList();
   bool parseAsNeeded(std::vector<Path> &paths);
 
   /// Parse the ENTRY linker script command.

Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Tue Feb  3 17:00:19 2015
@@ -240,18 +240,17 @@ static bool isPathUnderSysroot(StringRef
 }
 
 static std::error_code
-evaluateLinkerScriptGroup(ELFLinkingContext &ctx, StringRef path,
-                          const script::Group *group, raw_ostream &diag) {
+addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath,
+                         const std::vector<script::Path> &inputPaths,
+                         raw_ostream &diag) {
   bool sysroot = (!ctx.getSysroot().empty()
-                  && isPathUnderSysroot(ctx.getSysroot(), path));
-  int numfiles = 0;
-  for (const script::Path &path : group->getPaths()) {
+                  && isPathUnderSysroot(ctx.getSysroot(), scriptPath));
+  for (const script::Path &path : inputPaths) {
     ErrorOr<StringRef> pathOrErr = path._isDashlPrefix
       ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot);
     if (std::error_code ec = pathOrErr.getError()) {
       auto file = llvm::make_unique<ErrorFile>(path._path, ec);
       ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
-      ++numfiles;
       continue;
     }
 
@@ -261,10 +260,8 @@ evaluateLinkerScriptGroup(ELFLinkingCont
       if (ctx.logInputFiles())
         diag << file->path() << "\n";
       ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
-      ++numfiles;
     }
   }
-  ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(numfiles));
   return std::error_code();
 }
 
@@ -283,9 +280,18 @@ GnuLdDriver::evalLinkerScript(ELFLinking
   // Evaluate script commands.
   // Currently we only recognize this subset of linker script commands.
   for (const script::Command *c : script->_commands) {
-    if (auto *group = dyn_cast<script::Group>(c))
-      if (std::error_code ec = evaluateLinkerScriptGroup(ctx, path, group, diag))
+    if (auto *input = dyn_cast<script::Input>(c))
+      if (std::error_code ec = addFilesFromLinkerScript(
+            ctx, path, input->getPaths(), diag))
         return ec;
+    if (auto *group = dyn_cast<script::Group>(c)) {
+      int origSize = ctx.getNodes().size();
+      if (std::error_code ec = addFilesFromLinkerScript(
+            ctx, path, group->getPaths(), diag))
+        return ec;
+      size_t groupSize = ctx.getNodes().size() - origSize;
+      ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(groupSize));
+    }
     if (auto *searchDir = dyn_cast<script::SearchDir>(c))
       ctx.addSearchPath(searchDir->getSearchPath());
     if (auto *entry = dyn_cast<script::Entry>(c))

Modified: lld/trunk/lib/ReaderWriter/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (original)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Tue Feb  3 17:00:19 2015
@@ -64,6 +64,7 @@ void Token::dump(raw_ostream &os) const
     CASE(kw_exclude_file)
     CASE(kw_group)
     CASE(kw_hidden)
+    CASE(kw_input)
     CASE(kw_keep)
     CASE(kw_provide)
     CASE(kw_provide_hidden)
@@ -513,6 +514,7 @@ void Lexer::lex(Token &tok) {
             .Case("EXCLUDE_FILE", Token::kw_exclude_file)
             .Case("GROUP", Token::kw_group)
             .Case("HIDDEN", Token::kw_hidden)
+            .Case("INPUT", Token::kw_input)
             .Case("KEEP", Token::kw_keep)
             .Case("ONLY_IF_RO", Token::kw_only_if_ro)
             .Case("ONLY_IF_RW", Token::kw_only_if_rw)
@@ -924,8 +926,15 @@ std::error_code Parser::parse() {
       _script._commands.push_back(outputArch);
       break;
     }
+    case Token::kw_input: {
+      Input *input = parsePathList<Input>();
+      if (!input)
+        return LinkerScriptReaderError::parse_error;
+      _script._commands.push_back(input);
+      break;
+    }
     case Token::kw_group: {
-      auto group = parseGroup();
+      Group *group = parsePathList<Group>();
       if (!group)
         return LinkerScriptReaderError::parse_error;
       _script._commands.push_back(group);
@@ -1295,15 +1304,13 @@ OutputArch *Parser::parseOutputArch() {
   return ret;
 }
 
-// Parse GROUP(file ...)
-Group *Parser::parseGroup() {
-  assert(_tok._kind == Token::kw_group && "Expected GROUP!");
+// Parse file list for INPUT or GROUP
+template<class T> T *Parser::parsePathList() {
   consumeToken();
   if (!expectAndConsume(Token::l_paren, "expected ("))
     return nullptr;
 
   std::vector<Path> paths;
-
   while (_tok._kind == Token::identifier || _tok._kind == Token::libname ||
          _tok._kind == Token::kw_as_needed) {
     switch (_tok._kind) {
@@ -1323,13 +1330,9 @@ Group *Parser::parseGroup() {
       llvm_unreachable("Invalid token.");
     }
   }
-
-  auto ret = new (_alloc) Group(paths);
-
   if (!expectAndConsume(Token::r_paren, "expected )"))
     return nullptr;
-
-  return ret;
+  return new (_alloc) T(paths);
 }
 
 // Parse AS_NEEDED(file ...)

Modified: lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp?rev=228060&r1=228059&r2=228060&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/GnuLdDriverTest.cpp Tue Feb  3 17:00:19 2015
@@ -181,6 +181,14 @@ TEST_F(GnuLdParserTest, AsNeeded) {
 
 // Linker script
 
+TEST_F(LinkerScriptTest, Input) {
+  parse("INPUT(/x /y)");
+  std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();
+  EXPECT_EQ((size_t)2, nodes.size());
+  EXPECT_EQ("/x", cast<FileNode>(nodes[0].get())->getFile()->path());
+  EXPECT_EQ("/y", cast<FileNode>(nodes[1].get())->getFile()->path());
+}
+
 TEST_F(LinkerScriptTest, Group) {
   parse("GROUP(/x /y)");
   std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();





More information about the llvm-commits mailing list