[lld] r207297 - [PECOFF] Allow multiple directives in one module-definition file.

Rui Ueyama ruiu at google.com
Fri Apr 25 17:25:02 PDT 2014


Author: ruiu
Date: Fri Apr 25 19:25:02 2014
New Revision: 207297

URL: http://llvm.org/viewvc/llvm-project?rev=207297&view=rev
Log:
[PECOFF] Allow multiple directives in one module-definition file.

I'm a bit surprised that I have not implemented this yet. This is
definitely needed to handle real-world module definition files.
This patch contains a unit test for r207294.

Modified:
    lld/trunk/include/lld/Driver/WinLinkModuleDef.h
    lld/trunk/lib/Driver/WinLinkDriver.cpp
    lld/trunk/lib/Driver/WinLinkModuleDef.cpp
    lld/trunk/unittests/DriverTests/WinLinkModuleDefTest.cpp

Modified: lld/trunk/include/lld/Driver/WinLinkModuleDef.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/WinLinkModuleDef.h?rev=207297&r1=207296&r2=207297&view=diff
==============================================================================
--- lld/trunk/include/lld/Driver/WinLinkModuleDef.h (original)
+++ lld/trunk/include/lld/Driver/WinLinkModuleDef.h Fri Apr 25 19:25:02 2014
@@ -20,6 +20,8 @@
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/Allocator.h"
 
+#include <vector>
+
 namespace lld {
 namespace moduledef {
 
@@ -171,7 +173,7 @@ public:
   Parser(Lexer &lex, llvm::BumpPtrAllocator &alloc)
       : _lex(lex), _alloc(alloc) {}
 
-  llvm::Optional<Directive *> parse();
+  bool parse(std::vector<Directive *> &ret);
 
 private:
   void consumeToken();
@@ -181,6 +183,7 @@ private:
   void ungetToken();
   void error(const Token &tok, Twine msg);
 
+  bool parseOne(Directive *&dir);
   bool parseExport(PECOFFLinkingContext::ExportDesc &result);
   bool parseMemorySize(uint64_t &reserve, uint64_t &commit);
   bool parseName(std::string &outfile, uint64_t &baseaddr);

Modified: lld/trunk/lib/Driver/WinLinkDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/WinLinkDriver.cpp?rev=207297&r1=207296&r2=207297&view=diff
==============================================================================
--- lld/trunk/lib/Driver/WinLinkDriver.cpp (original)
+++ lld/trunk/lib/Driver/WinLinkDriver.cpp Fri Apr 25 19:25:02 2014
@@ -351,14 +351,14 @@ static bool parseExport(StringRef option
 }
 
 // Read module-definition file.
-static llvm::Optional<moduledef::Directive *>
-parseDef(StringRef option, llvm::BumpPtrAllocator &alloc) {
+static bool parseDef(StringRef option, llvm::BumpPtrAllocator &alloc,
+                     std::vector<moduledef::Directive *> &result) {
   std::unique_ptr<MemoryBuffer> buf;
   if (MemoryBuffer::getFile(option, buf))
     return llvm::None;
   moduledef::Lexer lexer(std::move(buf));
   moduledef::Parser parser(lexer, alloc);
-  return parser.parse();
+  return parser.parse(result);
 }
 
 static StringRef replaceExtension(PECOFFLinkingContext &ctx, StringRef path,
@@ -1050,37 +1050,37 @@ bool WinLinkDriver::parse(int argc, cons
 
     case OPT_deffile: {
       llvm::BumpPtrAllocator alloc;
-      llvm::Optional<moduledef::Directive *> dir =
-          parseDef(inputArg->getValue(), alloc);
-      if (!dir.hasValue()) {
+      std::vector<moduledef::Directive *> dirs;
+      if (!parseDef(inputArg->getValue(), alloc, dirs)) {
         diag << "Error: invalid module-definition file\n";
         return false;
       }
-
-      if (auto *exp = dyn_cast<moduledef::Exports>(dir.getValue())) {
-        for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) {
-          desc.name = ctx.decorateSymbol(desc.name);
-          ctx.addDllExport(desc);
+      for (moduledef::Directive *dir : dirs) {
+        if (auto *exp = dyn_cast<moduledef::Exports>(dir)) {
+          for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) {
+            desc.name = ctx.decorateSymbol(desc.name);
+            ctx.addDllExport(desc);
+          }
+        } else if (auto *hs = dyn_cast<moduledef::Heapsize>(dir)) {
+          ctx.setHeapReserve(hs->getReserve());
+          ctx.setHeapCommit(hs->getCommit());
+        } else if (auto *lib = dyn_cast<moduledef::Library>(dir)) {
+          ctx.setIsDll(true);
+          ctx.setOutputPath(ctx.allocate(lib->getName()));
+          if (lib->getBaseAddress() && !ctx.getBaseAddress())
+            ctx.setBaseAddress(lib->getBaseAddress());
+        } else if (auto *name = dyn_cast<moduledef::Name>(dir)) {
+          if (!name->getOutputPath().empty() && ctx.outputPath().empty())
+            ctx.setOutputPath(ctx.allocate(name->getOutputPath()));
+          if (name->getBaseAddress() && ctx.getBaseAddress())
+            ctx.setBaseAddress(name->getBaseAddress());
+        } else if (auto *ver = dyn_cast<moduledef::Version>(dir)) {
+          ctx.setImageVersion(PECOFFLinkingContext::Version(
+              ver->getMajorVersion(), ver->getMinorVersion()));
+        } else {
+          llvm::dbgs() << static_cast<int>(dir->getKind()) << "\n";
+          llvm_unreachable("Unknown module-definition directive.\n");
         }
-      } else if (auto *hs = dyn_cast<moduledef::Heapsize>(dir.getValue())) {
-        ctx.setHeapReserve(hs->getReserve());
-        ctx.setHeapCommit(hs->getCommit());
-      } else if (auto *lib = dyn_cast<moduledef::Library>(dir.getValue())) {
-        ctx.setIsDll(true);
-        ctx.setOutputPath(ctx.allocate(lib->getName()));
-        if (lib->getBaseAddress() && !ctx.getBaseAddress())
-          ctx.setBaseAddress(lib->getBaseAddress());
-      } else if (auto *name = dyn_cast<moduledef::Name>(dir.getValue())) {
-        if (!name->getOutputPath().empty() && ctx.outputPath().empty())
-          ctx.setOutputPath(ctx.allocate(name->getOutputPath()));
-        if (name->getBaseAddress() && ctx.getBaseAddress())
-          ctx.setBaseAddress(name->getBaseAddress());
-      } else if (auto *ver = dyn_cast<moduledef::Version>(dir.getValue())) {
-        ctx.setImageVersion(PECOFFLinkingContext::Version(
-            ver->getMajorVersion(), ver->getMinorVersion()));
-      } else {
-        llvm::dbgs() << static_cast<int>(dir.getValue()->getKind()) << "\n";
-        llvm_unreachable("Unknown module-definition directive.\n");
       }
     }
 

Modified: lld/trunk/lib/Driver/WinLinkModuleDef.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/WinLinkModuleDef.cpp?rev=207297&r1=207296&r2=207297&view=diff
==============================================================================
--- lld/trunk/lib/Driver/WinLinkModuleDef.cpp (original)
+++ lld/trunk/lib/Driver/WinLinkModuleDef.cpp Fri Apr 25 19:25:02 2014
@@ -111,9 +111,22 @@ void Parser::error(const Token &tok, Twi
       msg);
 }
 
-llvm::Optional<Directive *> Parser::parse() {
+bool Parser::parse(std::vector<Directive *> &ret) {
+  for (;;) {
+    Directive *dir = nullptr;
+    if (!parseOne(dir))
+      return false;
+    if (!dir)
+      return true;
+    ret.push_back(dir);
+  }
+}
+
+bool Parser::parseOne(Directive *&ret) {
   consumeToken();
   switch (_tok._kind) {
+  case Kind::eof:
+    return true;
   case Kind::kw_exports: {
     // EXPORTS
     std::vector<PECOFFLinkingContext::ExportDesc> exports;
@@ -123,48 +136,54 @@ llvm::Optional<Directive *> Parser::pars
         break;
       exports.push_back(desc);
     }
-    return new (_alloc) Exports(exports);
+    ret = new (_alloc) Exports(exports);
+    return true;
   }
   case Kind::kw_heapsize: {
     // HEAPSIZE
     uint64_t reserve, commit;
     if (!parseMemorySize(reserve, commit))
-      return llvm::None;
-    return new (_alloc) Heapsize(reserve, commit);
+      return false;
+    ret = new (_alloc) Heapsize(reserve, commit);
+    return true;
   }
   case Kind::kw_library: {
     // LIBRARY
     std::string name;
     uint64_t baseaddr;
     if (!parseName(name, baseaddr))
-      return llvm::None;
-    return new (_alloc) Library(name, baseaddr);
+      return false;
+    ret = new (_alloc) Library(name, baseaddr);
+    return true;
   }
   case Kind::kw_stacksize: {
     // STACKSIZE
     uint64_t reserve, commit;
     if (!parseMemorySize(reserve, commit))
-      return llvm::None;
-    return new (_alloc) Stacksize(reserve, commit);
+      return false;
+    ret = new (_alloc) Stacksize(reserve, commit);
+    return true;
   }
   case Kind::kw_name: {
     // NAME
     std::string outputPath;
     uint64_t baseaddr;
     if (!parseName(outputPath, baseaddr))
-      return llvm::None;
-    return new (_alloc) Name(outputPath, baseaddr);
+      return false;
+    ret = new (_alloc) Name(outputPath, baseaddr);
+    return true;
   }
   case Kind::kw_version: {
     // VERSION
     int major, minor;
     if (!parseVersion(major, minor))
-      return llvm::None;
-    return new (_alloc) Version(major, minor);
+      return false;
+    ret = new (_alloc) Version(major, minor);
+    return true;
   }
   default:
     error(_tok, Twine("Unknown directive: ") + _tok._range);
-    return llvm::None;
+    return false;
   }
 }
 
@@ -219,16 +238,19 @@ bool Parser::parseName(std::string &outp
   consumeToken();
   if (_tok._kind == Kind::identifier) {
     outputPath = _tok._range;
-    consumeToken();
   } else {
     outputPath = "";
+    ungetToken();
+    return true;
   }
+  consumeToken();
   if (_tok._kind == Kind::kw_base) {
     if (!expectAndConsume(Kind::equal, "'=' expected"))
       return false;
     if (!consumeTokenAsInt(baseaddr))
       return false;
   } else {
+    ungetToken();
     baseaddr = 0;
   }
   return true;

Modified: lld/trunk/unittests/DriverTests/WinLinkModuleDefTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/WinLinkModuleDefTest.cpp?rev=207297&r1=207296&r2=207297&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/WinLinkModuleDefTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/WinLinkModuleDefTest.cpp Fri Apr 25 19:25:02 2014
@@ -16,26 +16,19 @@
 using namespace llvm;
 using namespace lld;
 
-template <typename T> class ParserTest : public testing::Test {
+class ParserTest : public testing::Test {
 protected:
-  T *parse(const char *contents) {
+  std::vector<moduledef::Directive *> _dirs;
+
+  void parse(const char *contents) {
     auto membuf =
         std::unique_ptr<MemoryBuffer>(MemoryBuffer::getMemBuffer(contents));
     moduledef::Lexer lexer(std::move(membuf));
     moduledef::Parser parser(lexer, _alloc);
-    llvm::Optional<moduledef::Directive *> dir = parser.parse();
-    EXPECT_TRUE(dir.hasValue());
-    T *ret = dyn_cast<T>(dir.getValue());
-    EXPECT_TRUE(ret != nullptr);
-    return ret;
+    EXPECT_TRUE(parser.parse(_dirs));
+    EXPECT_TRUE(!_dirs.empty());
   }
 
-private:
-  llvm::BumpPtrAllocator _alloc;
-};
-
-class ExportsTest : public ParserTest<moduledef::Exports> {
-public:
   void verifyExportDesc(const PECOFFLinkingContext::ExportDesc &exp,
                         StringRef sym, int ordinal, bool noname, bool isData) {
     EXPECT_EQ(sym, exp.name);
@@ -43,22 +36,21 @@ public:
     EXPECT_EQ(noname, exp.noname);
     EXPECT_EQ(isData, exp.isData);
   }
+
+private:
+  llvm::BumpPtrAllocator _alloc;
 };
 
-class HeapsizeTest : public ParserTest<moduledef::Heapsize> {};
-class StacksizeTest : public ParserTest<moduledef::Stacksize> {};
-class NameTest : public ParserTest<moduledef::Name> {};
-class VersionTest : public ParserTest<moduledef::Version> {};
-
-TEST_F(ExportsTest, Basic) {
-  moduledef::Exports *dir = parse("EXPORTS\n"
-                                  "  sym1\n"
-                                  "  sym2 @5\n"
-                                  "  sym3 @8 NONAME\n"
-                                  "  sym4 DATA\n"
-                                  "  sym5 @10 NONAME DATA\n");
+TEST_F(ParserTest, Exports) {
+  parse("EXPORTS\n"
+        "  sym1\n"
+        "  sym2 @5\n"
+        "  sym3 @8 NONAME\n"
+        "  sym4 DATA\n"
+        "  sym5 @10 NONAME DATA\n");
+  EXPECT_EQ(1U, _dirs.size());
   const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
-      dir->getExports();
+      cast<moduledef::Exports>(_dirs[0])->getExports();
   EXPECT_EQ(5U, exports.size());
   verifyExportDesc(exports[0], "sym1", -1, false, false);
   verifyExportDesc(exports[1], "sym2", 5, false, false);
@@ -67,56 +59,98 @@ TEST_F(ExportsTest, Basic) {
   verifyExportDesc(exports[4], "sym5", 10, true, true);
 }
 
-TEST_F(HeapsizeTest, Basic) {
-  moduledef::Heapsize *heapsize = parse("HEAPSIZE 65536");
+TEST_F(ParserTest, Heapsize) {
+  parse("HEAPSIZE 65536");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *heapsize = cast<moduledef::Heapsize>(_dirs[0]);
   EXPECT_EQ(65536U, heapsize->getReserve());
   EXPECT_EQ(0U, heapsize->getCommit());
 }
 
-TEST_F(HeapsizeTest, WithCommit) {
-  moduledef::Heapsize *heapsize = parse("HEAPSIZE 65536, 8192");
+TEST_F(ParserTest, HeapsizeWithCommit) {
+  parse("HEAPSIZE 65536, 8192");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *heapsize = cast<moduledef::Heapsize>(_dirs[0]);
   EXPECT_EQ(65536U, heapsize->getReserve());
   EXPECT_EQ(8192U, heapsize->getCommit());
 }
 
-TEST_F(StacksizeTest, Basic) {
-  moduledef::Stacksize *stacksize = parse("STACKSIZE 65536");
+TEST_F(ParserTest, StacksizeBasic) {
+  parse("STACKSIZE 65536");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *stacksize = cast<moduledef::Stacksize>(_dirs[0]);
   EXPECT_EQ(65536U, stacksize->getReserve());
   EXPECT_EQ(0U, stacksize->getCommit());
 }
 
-TEST_F(StacksizeTest, WithCommit) {
-  moduledef::Stacksize *stacksize = parse("STACKSIZE 65536, 8192");
+TEST_F(ParserTest, StacksizeWithCommit) {
+  parse("STACKSIZE 65536, 8192");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *stacksize = cast<moduledef::Stacksize>(_dirs[0]);
   EXPECT_EQ(65536U, stacksize->getReserve());
   EXPECT_EQ(8192U, stacksize->getCommit());
 }
 
-TEST_F(NameTest, Basic) {
-  moduledef::Name *name = parse("NAME foo.exe");
+TEST_F(ParserTest, Library) {
+  parse("LIBRARY foo.dll");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *lib = cast<moduledef::Library>(_dirs[0]);
+  EXPECT_EQ("foo.dll", lib->getName());
+}
+
+TEST_F(ParserTest, NameBasic) {
+  parse("NAME foo.exe");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *name = cast<moduledef::Name>(_dirs[0]);
   EXPECT_EQ("foo.exe", name->getOutputPath());
   EXPECT_EQ(0U, name->getBaseAddress());
 }
 
-TEST_F(NameTest, WithBase) {
-  moduledef::Name *name = parse("NAME foo.exe BASE=4096");
+TEST_F(ParserTest, NameWithBase) {
+  parse("NAME foo.exe BASE=4096");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *name = cast<moduledef::Name>(_dirs[0]);
   EXPECT_EQ("foo.exe", name->getOutputPath());
   EXPECT_EQ(4096U, name->getBaseAddress());
 }
 
-TEST_F(NameTest, LongFileName) {
-  moduledef::Name *name = parse("NAME \"a long file name.exe\"");
+TEST_F(ParserTest, NameLongFileName) {
+  parse("NAME \"a long file name.exe\"");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *name = cast<moduledef::Name>(_dirs[0]);
   EXPECT_EQ("a long file name.exe", name->getOutputPath());
   EXPECT_EQ(0U, name->getBaseAddress());
 }
 
-TEST_F(VersionTest, Major) {
-  moduledef::Version *ver = parse("VERSION 12");
+TEST_F(ParserTest, VersionMajor) {
+  parse("VERSION 12");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *ver = cast<moduledef::Version>(_dirs[0]);
   EXPECT_EQ(12, ver->getMajorVersion());
   EXPECT_EQ(0, ver->getMinorVersion());
 }
 
-TEST_F(VersionTest, MajorMinor) {
-  moduledef::Version *ver = parse("VERSION 12.34");
+TEST_F(ParserTest, VersionMajorMinor) {
+  parse("VERSION 12.34");
+  EXPECT_EQ(1U, _dirs.size());
+  auto *ver = cast<moduledef::Version>(_dirs[0]);
   EXPECT_EQ(12, ver->getMajorVersion());
   EXPECT_EQ(34, ver->getMinorVersion());
 }
+
+TEST_F(ParserTest, Multiple) {
+  parse("LIBRARY foo\n"
+        "EXPORTS sym\n"
+        "VERSION 12");
+  EXPECT_EQ(3U, _dirs.size());
+  auto *lib = cast<moduledef::Library>(_dirs[0]);
+  EXPECT_EQ("foo", lib->getName());
+
+  const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
+      cast<moduledef::Exports>(_dirs[1])->getExports();
+  EXPECT_EQ(1U, exports.size());
+  verifyExportDesc(exports[0], "sym", -1, false, false);
+
+  auto *ver = cast<moduledef::Version>(_dirs[2]);
+  EXPECT_EQ(12, ver->getMajorVersion());
+}





More information about the llvm-commits mailing list