COFF: Add /failifmismatch option.
authorRui Ueyama <ruiu@google.com>
Thu, 4 Jun 2015 19:21:24 +0000 (19:21 +0000)
committerRui Ueyama <ruiu@google.com>
Thu, 4 Jun 2015 19:21:24 +0000 (19:21 +0000)
llvm-svn: 239073

lld/COFF/Config.h
lld/COFF/Driver.cpp
lld/COFF/Driver.h
lld/COFF/DriverUtils.cpp
lld/test/COFF/failifmismatch.test [new file with mode: 0644]

index 66ffa65..a49906c 100644 (file)
@@ -13,6 +13,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/COFF.h"
 #include <cstdint>
+#include <map>
 #include <set>
 #include <string>
 
@@ -35,6 +36,9 @@ public:
   std::set<StringRef> NoDefaultLibs;
   bool NoDefaultLibAll = false;
 
+  // Used by /failifmismatch option.
+  std::map<StringRef, StringRef> MustMatch;
+
   uint64_t ImageBase = 0x140000000;
   uint64_t StackReserve = 1024 * 1024;
   uint64_t StackCommit = 4096;
index 659249f..0700f1a 100644 (file)
@@ -110,6 +110,11 @@ LinkerDriver::parseDirectives(StringRef S,
     return EC;
   std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());
 
+  // Handle /failifmismatch
+  if (auto EC = checkFailIfMismatch(Args.get()))
+    return EC;
+
+  // Handle /defaultlib
   for (auto *Arg : Args->filtered(OPT_defaultlib)) {
     if (Optional<StringRef> Path = findLib(Arg->getValue())) {
       auto FileOrErr = openFile(*Path);
@@ -297,6 +302,12 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
     }
   }
 
+  // Handle /failifmismatch
+  if (auto EC = checkFailIfMismatch(Args.get())) {
+    llvm::errs() << "/failifmismatch: " << EC.message() << "\n";
+    return false;
+  }
+
   // Create a list of input files. Files can be given as arguments
   // for /defaultlib option.
   std::vector<StringRef> Inputs;
index 09213c7..3186074 100644 (file)
@@ -90,6 +90,12 @@ std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
 std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
                                uint32_t *Major, uint32_t *Minor);
 
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the key.
+// This feature used in the directive section to reject
+// incompatible objects.
+std::error_code checkFailIfMismatch(llvm::opt::InputArgList *Args);
+
 // Create enum with OPT_xxx values for each option in Options.td
 enum {
   OPT_INVALID = 0,
index 0f58a33..0fc6f2f 100644 (file)
@@ -13,6 +13,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Config.h"
 #include "Driver.h"
 #include "Error.h"
 #include "Memory.h"
@@ -112,6 +113,29 @@ std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
   return std::error_code();
 }
 
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the same key.
+std::error_code checkFailIfMismatch(llvm::opt::InputArgList *Args) {
+  for (auto *Arg : Args->filtered(OPT_failifmismatch)) {
+    StringRef K, V;
+    std::tie(K, V) = StringRef(Arg->getValue()).split('=');
+    if (K.empty() || V.empty()) {
+      llvm::errs() << "/failifmismatch: invalid argument: "
+                   << Arg->getValue() << "\n";
+      return make_error_code(LLDError::InvalidOption);
+    }
+    StringRef Existing = Config->MustMatch[K];
+    if (!Existing.empty() && V != Existing) {
+      llvm::errs() << "/failifmismatch: mismatch detected: "
+                   << Existing << " and " << V
+                   << " for key " << K << "\n";
+      return make_error_code(LLDError::InvalidOption);
+    }
+    Config->MustMatch[K] = V;
+  }
+  return std::error_code();
+}
+
 // Create OptTable
 
 // Create prefix string literals used in Options.td
diff --git a/lld/test/COFF/failifmismatch.test b/lld/test/COFF/failifmismatch.test
new file mode 100644 (file)
index 0000000..91a6fbc
--- /dev/null
@@ -0,0 +1,11 @@
+# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj
+
+# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1
+
+# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1
+
+# RUN: not lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2