[PECOFF] Define implicit symbols for exported ones.

This patch is to fix a compatibility issue with MSVC link.exe as to
use of dllexported symbols inside DLL.

A DLL exports two symbols for a function. One is non-decorated one,
and the other is with __imp_ prefix. The former is a function that
you can directly call, and the latter is a pointer to the function.
These dllexported symbols are created by linker for programs that
link against the DLL. So, I naturally believed that __imp_ symbols
become available when you once create a DLL and link against it, but
they don't exist until then. And that's not true.

MSVC link.exe is smart enough to allow users to use __imp_ symbols
locally. That is, if a symbol is specified with /export option, it
implicitly creates a new symbol with __imp_ prefix as a pointer to
the exported symbol. This feature allows the following program to
be linked and run, although _imp__hello is not defined in this code.

  #include <stdio.h>

  __declspec(dllexport)
  void hello(void) { printf("Hello\n"); }

  extern void (*_imp__hello)(void);

  int main() {
    _imp__hello();
    return 0;
  }

MSVC link.exe prints out the following warning when linking it.

  LNK4217: locally defined symbol _hello imported in function _main

Using __imp_ symbols locally is I think not a good coding style. One
should just take an address using "&" operator rather than appending
__imp_ prefix. However, there are programs in the wild that depends
on this link.exe's behavior, so we need this feature.

llvm-svn: 207141
diff --git a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
index 248aaab..5b9464b 100644
--- a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
+++ b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
@@ -11,10 +11,25 @@
 
 #include "lld/ReaderWriter/PECOFFLinkingContext.h"
 #include "lld/ReaderWriter/Simple.h"
+#include "llvm/Support/Allocator.h"
 
 namespace lld {
 namespace pecoff {
 
+/// The defined atom for dllexported symbols with __imp_ prefix.
+class ImpPointerAtom : public COFFLinkerInternalAtom {
+public:
+  ImpPointerAtom(const File &file, StringRef symbolName)
+      : COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
+                               symbolName) {}
+
+  uint64_t ordinal() const override { return 0; }
+  Scope scope() const override { return scopeGlobal; }
+  ContentType contentType() const override { return typeData; }
+  Alignment alignment() const override { return Alignment(4); }
+  ContentPermissions permissions() const override { return permR__; }
+};
+
 // A virtual file containing absolute symbol __ImageBase. __ImageBase (or
 // ___ImageBase on x86) is a linker-generated symbol whose address is the same
 // as the image base address.
@@ -25,10 +40,29 @@
         _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
                        Atom::scopeGlobal, ctx.getBaseAddress()) {
     addAtom(_imageBaseAtom);
+
+    // Create implciit symbols for exported symbols.
+    for (const PECOFFLinkingContext::ExportDesc exp : ctx.getDllExports()) {
+      UndefinedAtom *target = new (_alloc) SimpleUndefinedAtom(*this, exp.name);
+      COFFLinkerInternalAtom *imp = createImpPointerAtom(ctx, exp.name);
+      imp->addReference(std::unique_ptr<COFFReference>(
+          new COFFReference(target, 0, llvm::COFF::IMAGE_REL_I386_DIR32)));
+      addAtom(*target);
+      addAtom(*imp);
+    }
   };
 
 private:
+  COFFLinkerInternalAtom *createImpPointerAtom(const PECOFFLinkingContext &ctx,
+                                               StringRef name) {
+    std::string sym = "_imp_";
+    sym.append(name);
+    sym = ctx.decorateSymbol(sym);
+    return new (_alloc) ImpPointerAtom(*this, ctx.allocate(sym));
+  }
+
   COFFAbsoluteAtom _imageBaseAtom;
+  llvm::BumpPtrAllocator _alloc;
 };
 
 } // end namespace pecoff