[PECOFF] Fix /include option in .drectve section.
authorRui Ueyama <ruiu@google.com>
Mon, 4 Aug 2014 23:48:57 +0000 (23:48 +0000)
committerRui Ueyama <ruiu@google.com>
Mon, 4 Aug 2014 23:48:57 +0000 (23:48 +0000)
/INCLUDE arguments passed as command line options are handled in the
same way as Unix -u. All option values are converted to an undefined
symbol and added to a dummy input file, so that the specified symbols
are resolved.

One tricky thing on Windows is that the option is also allowed to
appear in the object file's directive section. At the time when
it's being read, all (regular) command line options have already
been processed. We cannot add undefined atoms to the dummy file
anymore.

Previously, we added such /INCLUDE to a set that has already been
processed. As a result the options were ignored.

This patch fixes the issue. Now, /INCLUDE symbols in the directive
section are handled as real undefined symbol in the COFF file.
We create an undefined symbol for each /INCLUDE argument and add
it to the file being parsed.

llvm-svn: 214824

lld/include/lld/Driver/Driver.h
lld/lib/Driver/WinLinkDriver.cpp
lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
lld/test/pecoff/Inputs/drectve2.obj.yaml [new file with mode: 0644]
lld/test/pecoff/drectve.test

index 7ea6029..fa8ab72 100644 (file)
@@ -24,6 +24,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 #include <memory>
+#include <set>
 #include <vector>
 
 namespace lld {
@@ -112,7 +113,8 @@ public:
   /// Returns true iff there was an error.
   static bool parse(int argc, const char *argv[], PECOFFLinkingContext &info,
                     raw_ostream &diagnostics = llvm::errs(),
-                    bool isDirective = false);
+                    bool isDirective = false,
+                    std::set<StringRef> *undefinedSymbols = nullptr);
 
 private:
   WinLinkDriver() LLVM_DELETED_FUNCTION;
index 66fbcb2..330b806 100644 (file)
@@ -811,7 +811,8 @@ bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
 
 bool WinLinkDriver::parse(int argc, const char *argv[],
                           PECOFFLinkingContext &ctx, raw_ostream &diag,
-                          bool isReadingDirectiveSection) {
+                          bool isReadingDirectiveSection,
+                          std::set<StringRef> *undefinedSymbols) {
   // Parse may be called from multiple threads simultaneously to parse .drectve
   // sections. This function is not thread-safe because it mutates the context
   // object. So acquire the lock.
@@ -1183,9 +1184,15 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
       break;
     }
 
-    case OPT_incl:
-      ctx.addInitialUndefinedSymbol(ctx.allocate(inputArg->getValue()));
+    case OPT_incl: {
+      StringRef sym = ctx.allocate(inputArg->getValue());
+      if (isReadingDirectiveSection) {
+        undefinedSymbols->insert(sym);
+      } else {
+        ctx.addInitialUndefinedSymbol(sym);
+      }
       break;
+    }
 
     case OPT_noentry:
       ctx.setHasEntry(false);
index c8243a2..84d3f5f 100644 (file)
@@ -92,6 +92,10 @@ public:
     _definedAtoms._atoms.push_back(atom);
   }
 
+  void addUndefinedSymbol(StringRef sym) {
+    _undefinedAtoms._atoms.push_back(new (_alloc) COFFUndefinedAtom(*this, sym));
+  }
+
   mutable llvm::BumpPtrAllocator _alloc;
 
 private:
@@ -954,10 +958,15 @@ public:
     if (ec)
       return ec;
 
+    // The set to contain the symbols specified as arguments of
+    // /INCLUDE option.
+    std::set<StringRef> undefinedSymbols;
+
     // Interpret .drectve section if the section has contents.
     StringRef directives = file->getLinkerDirectives();
     if (!directives.empty())
-      if (std::error_code ec = handleDirectiveSection(directives))
+      if (std::error_code ec = handleDirectiveSection(
+              directives, &undefinedSymbols))
         return ec;
 
     if (std::error_code ec = file->parse())
@@ -980,6 +989,12 @@ public:
     // function iterate over defined atoms and create alias atoms if needed.
     createAlternateNameAtoms(*file);
 
+    for (StringRef sym : undefinedSymbols) {
+      file->addUndefinedSymbol(sym);
+      if (_ctx.deadStrip())
+        _ctx.addDeadStripRoot(sym);
+    }
+
     result.push_back(std::move(file));
     return std::error_code();
   }
@@ -991,7 +1006,8 @@ private:
   //
   // The section mainly contains /defaultlib (-l in Unix), but can contain any
   // options as long as they are valid.
-  std::error_code handleDirectiveSection(StringRef directives) const {
+  std::error_code handleDirectiveSection(StringRef directives,
+                                         std::set<StringRef> *undefinedSymbols) const {
     DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
 
     // Split the string into tokens, as the shell would do for argv.
@@ -1007,7 +1023,8 @@ private:
     std::string errorMessage;
     llvm::raw_string_ostream stream(errorMessage);
     bool parseFailed = !WinLinkDriver::parse(argc, argv, _ctx, stream,
-                                             /*isDirective*/ true);
+                                             /*isDirective*/ true,
+                                             undefinedSymbols);
     stream.flush();
     // Print error message if error.
     if (parseFailed) {
diff --git a/lld/test/pecoff/Inputs/drectve2.obj.yaml b/lld/test/pecoff/Inputs/drectve2.obj.yaml
new file mode 100644 (file)
index 0000000..836cbc3
--- /dev/null
@@ -0,0 +1,45 @@
+---
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     558BEC56FF15000000008B0D000000008B3103F0FF150000000003C65E5DC3
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       2147483648
+    SectionData:     2f696e636c7564653a666f6f00
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          31
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        3595596940
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          13
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+...
index 3250312..a471206 100644 (file)
@@ -22,3 +22,11 @@ IMPORT-NEXT:        1  fn
 IMPORT-NEXT:        1
 
 ERROR-NOT: foo
+
+
+# drectve2.obj contains "/include:foo".
+# RUN: yaml2obj %p/Inputs/drectve2.obj.yaml > %t2.obj
+# RUN: not lld -flavor link /out:%t2.exe /entry:main -- %t2.obj >& %t2.log
+# RUN: FileCheck -check-prefix=UNDEF %s < %t2.log
+
+UNDEF: Undefined symbol: {{.*}}: foo