[PECOFF] Add /include command line option.
authorRui Ueyama <ruiu@google.com>
Wed, 24 Jul 2013 22:53:23 +0000 (22:53 +0000)
committerRui Ueyama <ruiu@google.com>
Wed, 24 Jul 2013 22:53:23 +0000 (22:53 +0000)
The /include command line option is equivalent to Unix --undefined
option, which forces the linker to resolve the given symbol name
as if it's an unresolved symbol in one of its input files. This feature
is used to link an additional object file or a shared library that no
input files refer to.

llvm-svn: 187084

lld/include/lld/ReaderWriter/PECOFFTargetInfo.h
lld/lib/Driver/WinLinkDriver.cpp
lld/lib/Driver/WinLinkOptions.td
lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp
lld/test/pecoff/include.test [new file with mode: 0644]
lld/unittests/DriverTests/WinLinkDriverTest.cpp

index f9a1729..c621992 100644 (file)
@@ -46,6 +46,8 @@ public:
 
   virtual void addPasses(PassManager &pm) const;
 
+  virtual void addImplicitFiles(InputFiles &) const;
+
   void appendInputSearchPath(StringRef dirPath) {
     _inputSearchPaths.push_back(dirPath);
   }
@@ -92,7 +94,7 @@ public:
   virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
 
   StringRef allocateString(const StringRef &ref) {
-    char *x = _extraStrings.Allocate<char>(ref.size() + 1);
+    char *x = _alloc.Allocate<char>(ref.size() + 1);
     memcpy(x, ref.data(), ref.size());
     x[ref.size()] = '\0';
     return x;
@@ -117,7 +119,7 @@ private:
   std::vector<StringRef> _inputSearchPaths;
   mutable std::unique_ptr<Reader> _reader;
   mutable std::unique_ptr<Writer> _writer;
-  llvm::BumpPtrAllocator _extraStrings;
+  mutable llvm::BumpPtrAllocator _alloc;
 };
 
 } // end namespace lld
index 8b235d3..0d017d0 100644 (file)
@@ -351,6 +351,10 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
   if (parsedArgs->getLastArg(OPT_no_tsaware))
     info.setTerminalServerAware(false);
 
+  // Handle -include
+  if (llvm::opt::Arg *sym = parsedArgs->getLastArg(OPT_incl))
+    info.addInitialUndefinedSymbol(sym->getValue());
+
   // Handle -out
   if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out))
     info.setOutputPath(outpath->getValue());
index f130230..0f0590e 100644 (file)
@@ -60,5 +60,9 @@ def tsaware : Flag<["-", "/"], "tsaware">,
 def no_tsaware : Flag<["-", "/"], "tsaware:no">,
     HelpText<"Create non-Terminal Server aware executable">;
 
+def incl : Separate<["-", "/"], "include">,
+    HelpText<"Force symbol to be added to symbol table as undefined one">;
+def incl_c : Joined<["-", "/"], "include:">, Alias<incl>;
+
 def help : Flag<["-", "/"], "help">;
 def help_q : Flag<["-", "/"], "?">, Alias<help>;
index a08d9ab..c58ee14 100644 (file)
@@ -7,15 +7,19 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Atoms.h"
 #include "GroupedSectionsPass.h"
 #include "IdataPass.h"
 
 #include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/Path.h"
+#include "lld/Core/InputFiles.h"
 #include "lld/Core/PassManager.h"
 #include "lld/Passes/LayoutPass.h"
 #include "lld/ReaderWriter/PECOFFTargetInfo.h"
 #include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Simple.h"
 #include "lld/ReaderWriter/Writer.h"
 
 namespace lld {
@@ -26,6 +30,24 @@ bool containDirectoryName(StringRef path) {
   llvm::sys::path::remove_filename(smallStr);
   return !smallStr.str().empty();
 }
+
+/// An instance of UndefinedSymbolFile has a list of undefined symbols
+/// specified by "/include" command line option. This will be added to the
+/// input file list to force the core linker to try to resolve the undefined
+/// symbols.
+class UndefinedSymbolFile : public SimpleFile {
+public:
+  UndefinedSymbolFile(const TargetInfo &ti)
+      : SimpleFile(ti, "Linker Internal File") {
+    for (StringRef symbol : ti.initialUndefinedSymbols()) {
+      UndefinedAtom *atom = new (_alloc) coff::COFFUndefinedAtom(*this, symbol);
+      addAtom(*atom);
+    }
+  };
+
+private:
+  llvm::BumpPtrAllocator _alloc;
+};
 } // anonymous namespace
 
 error_code PECOFFTargetInfo::parseFile(
@@ -59,6 +81,12 @@ bool PECOFFTargetInfo::validateImpl(raw_ostream &diagnostics) {
   return false;
 }
 
+void PECOFFTargetInfo::addImplicitFiles(InputFiles &files) const {
+  // Add a pseudo file for "/include" linker option.
+  auto *file = new (_alloc) UndefinedSymbolFile(*this);
+  files.prependFile(*file);
+}
+
 /// Append the given file to the input file list. The file must be an object
 /// file or an import library file.
 bool PECOFFTargetInfo::appendInputFileOrLibrary(std::string path) {
diff --git a/lld/test/pecoff/include.test b/lld/test/pecoff/include.test
new file mode 100644 (file)
index 0000000..ad7eada
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+#
+# RUN: not lld -flavor link -out %t1 -subsystem console \
+# RUN:   -include nosuchsym -- %t.obj 2> %t1
+# RUN: FileCheck %s < %t1
+
+CHECK: Undefined Symbol: Linker Internal File : nosuchsym
\ No newline at end of file
index 25d8170..d028bec 100644 (file)
@@ -54,6 +54,7 @@ TEST_F(WinLinkParserTest, Basic) {
   EXPECT_FALSE(_info.getLargeAddressAware());
   EXPECT_TRUE(_info.getBaseRelocationEnabled());
   EXPECT_TRUE(_info.isTerminalServerAware());
+  EXPECT_TRUE(_info.initialUndefinedSymbols().empty());
 }
 
 TEST_F(WinLinkParserTest, WindowsStyleOption) {
@@ -172,6 +173,15 @@ TEST_F(WinLinkParserTest, NoTerminalServerAware) {
   EXPECT_FALSE(_info.isTerminalServerAware());
 }
 
+TEST_F(WinLinkParserTest, Include) {
+  EXPECT_FALSE(parse("link.exe", "-include", "foo", "a.out", nullptr));
+  auto symbols = _info.initialUndefinedSymbols();
+  EXPECT_FALSE(symbols.empty());
+  EXPECT_EQ("foo", symbols[0]);
+  symbols.pop_front();
+  EXPECT_TRUE(symbols.empty());
+}
+
 TEST_F(WinLinkParserTest, NoInputFiles) {
   EXPECT_TRUE(parse("link.exe", nullptr));
   EXPECT_EQ("No input files\n", errorMessage());