[PECOFF] Support linking against DLL.
authorRui Ueyama <ruiu@google.com>
Thu, 11 Jul 2013 08:46:21 +0000 (08:46 +0000)
committerRui Ueyama <ruiu@google.com>
Thu, 11 Jul 2013 08:46:21 +0000 (08:46 +0000)
This patch adds a new pass, IdataPass, to transform shared atom references
to real references and to construct the .idata section data. With this patch
lld can produce a working Hello World program by linking it against
kernel32.dll and user32.dll.

Reviewers: Bigcheese

CC: llvm-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1096

llvm-svn: 186071

17 files changed:
lld/include/lld/Core/DefinedAtom.h
lld/lib/Core/DefinedAtom.cpp
lld/lib/ReaderWriter/PECOFF/Atoms.h
lld/lib/ReaderWriter/PECOFF/IdataPass.h [new file with mode: 0644]
lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp
lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
lld/test/pecoff/Inputs/dynamic.dll [deleted file]
lld/test/pecoff/Inputs/dynamic.lib [deleted file]
lld/test/pecoff/Inputs/grouped-sections.asm
lld/test/pecoff/Inputs/grouped-sections.obj.yaml
lld/test/pecoff/Inputs/vars-main.c [new file with mode: 0644]
lld/test/pecoff/Inputs/vars-main.obj.yaml [new file with mode: 0644]
lld/test/pecoff/Inputs/vars.c [new file with mode: 0644]
lld/test/pecoff/Inputs/vars.dll.yaml [new file with mode: 0644]
lld/test/pecoff/Inputs/vars.lib [new file with mode: 0644]
lld/test/pecoff/importlib.test

index 9ba2428..b4b2f87 100644 (file)
@@ -144,6 +144,7 @@ public:
     typeTLVInitialData,     // initial data for a TLV [Darwin]
     typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
     typeTLVInitializerPtr,  // pointer to thread local initializer [Darwin]
+    typeDataDirectoryEntry, // linker created for data directory header [PECOFF]
   };
 
   // Permission bits for atoms and segments. The order of these values are
index 0aa2aa8..9e00567 100644 (file)
@@ -51,6 +51,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
   case typeLazyPointer:
   case typeLazyDylibPointer:
   case typeThunkTLV:
+  case typeDataDirectoryEntry:
     return permRW_;
 
   case typeGOT:
index f7a99be..7ef7995 100644 (file)
@@ -223,27 +223,45 @@ public:
   virtual uint64_t ordinal() const { return 0; }
   virtual Scope scope() const { return scopeGlobal; }
   virtual Alignment alignment() const { return Alignment(1); }
-  virtual uint64_t size() const { return _data->size(); }
-  virtual ArrayRef<uint8_t> rawContent() const { return *_data; }
+  virtual uint64_t size() const { return _data.size(); }
+  virtual ArrayRef<uint8_t> rawContent() const { return _data; }
 
 protected:
-  COFFLinkerInternalAtom(const File &file, std::vector<uint8_t> *data,
+  COFFLinkerInternalAtom(const File &file, std::vector<uint8_t> data,
                          StringRef symbolName = "")
-      : COFFBaseDefinedAtom(file, symbolName, Kind::Internal), _data(data) {}
+      : COFFBaseDefinedAtom(file, symbolName, Kind::Internal),
+        _data(std::move(data)) {}
 
 private:
-  std::vector<uint8_t> *_data;
+  std::vector<uint8_t> _data;
+};
+
+// A COFFDataDirectoryAtom represents an entry of Optional Data Directory in the
+// COFF header.
+class COFFDataDirectoryAtom : public COFFLinkerInternalAtom {
+public:
+  COFFDataDirectoryAtom(const File &file, uint64_t ordinal)
+      : COFFLinkerInternalAtom(file, std::vector<uint8_t>(8)),
+        _ordinal(ordinal) {}
+
+  virtual uint64_t ordinal() const { return _ordinal; }
+  virtual ContentType contentType() const { return typeDataDirectoryEntry; }
+  virtual ContentPermissions permissions() const { return permR__; }
+
+private:
+  uint64_t _ordinal;
 };
 
 // A COFFSharedLibraryAtom represents a symbol for data in an import library.  A
 // reference to a COFFSharedLibraryAtom will be transformed to a real reference
-// to an import address table entry in a pass.
+// to an import address table entry in Idata pass.
 class COFFSharedLibraryAtom : public SharedLibraryAtom {
 public:
   COFFSharedLibraryAtom(const File &file, uint16_t hint,
                         StringRef symbolName, StringRef loadName)
       : _file(file), _hint(hint), _unmangledName(symbolName),
-        _loadName(loadName), _mangledName(addImpPrefix(symbolName)) {}
+        _loadName(loadName), _mangledName(addImpPrefix(symbolName)),
+        _importTableEntry(nullptr) {}
 
   virtual const File &file() const { return _file; }
   uint16_t hint() const { return _hint; }
@@ -252,6 +270,14 @@ public:
   virtual StringRef loadName() const { return _loadName; }
   virtual bool canBeNullAtRuntime() const { return false; }
 
+  void setImportTableEntry(const DefinedAtom *atom) {
+    _importTableEntry = atom;
+  }
+
+  const DefinedAtom *getImportTableEntry() const {
+    return _importTableEntry;
+  }
+
 private:
   /// Mangle the symbol name by adding "__imp_" prefix. See the file comment of
   /// ReaderImportHeader.cpp for details about the prefix.
@@ -266,6 +292,7 @@ private:
   StringRef _unmangledName;
   StringRef _loadName;
   std::string _mangledName;
+  const DefinedAtom *_importTableEntry;
 };
 
 //===----------------------------------------------------------------------===//
diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.h b/lld/lib/ReaderWriter/PECOFF/IdataPass.h
new file mode 100644 (file)
index 0000000..fd41552
--- /dev/null
@@ -0,0 +1,313 @@
+//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This linker pass creates atoms for the DLL import
+/// information. The defined atoms constructed in this pass will go into .idata
+/// section, unless .idata section is merged with other section such as .data.
+///
+/// For the details of the .idata section format, see Microsoft PE/COFF
+/// Specification section 5.4, The .idata Section.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H_
+#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H_
+
+#include "Atoms.h"
+
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Endian.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <map>
+
+using lld::coff::COFFBaseDefinedAtom;
+using lld::coff::COFFDefinedAtom;
+using lld::coff::COFFLinkerInternalAtom;
+using lld::coff::COFFReference;
+using lld::coff::COFFSharedLibraryAtom;
+using lld::coff::COFFSharedLibraryAtom;
+using llvm::COFF::ImportDirectoryTableEntry;
+using std::map;
+using std::vector;
+
+namespace lld {
+namespace pecoff {
+
+namespace {
+class DLLNameAtom;
+class HintNameAtom;
+class ImportTableEntryAtom;
+
+void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
+                     size_t offsetInAtom) {
+  atom->addReference(std::unique_ptr<COFFReference>(new COFFReference(
+      target, offsetInAtom, llvm::COFF::IMAGE_REL_I386_DIR32NB)));
+}
+
+// A state object of this pass.
+struct Context {
+  explicit Context(MutableFile &f) : file(f) {}
+
+  MutableFile &file;
+
+  // The object to accumulate idata atoms. Idata atoms need to be grouped by
+  // type and be continuous in the output file. To force such layout, we
+  // accumulate all atoms created in the pass in the following vectors, and add
+  // layout edges when finishing the pass.
+  vector<COFFBaseDefinedAtom *> importDirectories;
+  vector<ImportTableEntryAtom *> importLookupTables;
+  vector<ImportTableEntryAtom *> importAddressTables;
+  vector<HintNameAtom *> hintNameAtoms;
+  vector<DLLNameAtom *> dllNameAtoms;
+
+  map<StringRef, COFFBaseDefinedAtom *> sharedToDefinedAtom;
+};
+
+/// The root class of all idata atoms.
+class IdataAtom : public COFFLinkerInternalAtom {
+public:
+  virtual ContentType contentType() const { return typeData; }
+  virtual ContentPermissions permissions() const { return permR__; }
+
+protected:
+  IdataAtom(MutableFile &file, vector<uint8_t> data)
+      : COFFLinkerInternalAtom(file, data) {
+    file.addAtom(*this);
+  }
+};
+
+/// A DLLNameAtom contains a name of a DLL and is referenced by the Name RVA
+/// field in the import directory table entry.
+class DLLNameAtom : public IdataAtom {
+public:
+  DLLNameAtom(Context &ctx, StringRef name)
+      : IdataAtom(ctx.file, stringRefToVector(name)) {
+    ctx.dllNameAtoms.push_back(this);
+  }
+
+private:
+  vector<uint8_t> stringRefToVector(StringRef name) {
+    vector<uint8_t> ret(name.size() + 1);
+    memcpy(&ret[0], name.data(), name.size());
+    ret[name.size()] = 0;
+    return std::move(ret);
+  }
+};
+
+/// A HintNameAtom represents a symbol that will be imported from a DLL at
+/// runtime. It consists with an optional hint, which is a small integer, and a
+/// symbol name.
+///
+/// A hint is an index of the export pointer table in a DLL. If the import
+/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version
+/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF
+/// loader can find the symbol quickly.
+class HintNameAtom : public IdataAtom {
+public:
+  HintNameAtom(Context &ctx, uint16_t hint, StringRef name)
+      : IdataAtom(ctx.file, assembleRawContent(hint, name)), _name(name) {
+    ctx.hintNameAtoms.push_back(this);
+  }
+
+  StringRef getContentString() { return _name; }
+
+private:
+  // The first two bytes of the content is a hint, followed by a null-terminated
+  // symbol name. The total size needs to be multiple of 2.
+  vector<uint8_t> assembleRawContent(uint16_t hint, StringRef name) {
+    name = unmangle(name);
+    size_t size = llvm::RoundUpToAlignment(sizeof(hint) + name.size() + 1, 2);
+    vector<uint8_t> ret(size);
+    ret[name.size()] = 0;
+    ret[name.size() - 1] = 0;
+    *reinterpret_cast<llvm::support::ulittle16_t *>(&ret[0]) = hint;
+    std::memcpy(&ret[2], name.data(), name.size());
+    return ret;
+  }
+
+  /// Undo name mangling. In Windows, the symbol name for function is encoded
+  /// as "_name@X", where X is the number of bytes of the arguments.
+  StringRef unmangle(StringRef mangledName) {
+    assert(mangledName.startswith("_"));
+    return mangledName.substr(1).split('@').first;
+  }
+
+  StringRef _name;
+};
+
+class ImportTableEntryAtom : public IdataAtom {
+public:
+  explicit ImportTableEntryAtom(Context &ctx)
+      : IdataAtom(ctx.file, vector<uint8_t>(4, 0)) {}
+};
+
+/// An ImportDirectoryAtom includes information to load a DLL, including a DLL
+/// name, symbols that will be resolved from the DLL, and the import address
+/// table that are overwritten by the loader with the pointers to the referenced
+/// items. The executable has one ImportDirectoryAtom per one imported DLL.
+class ImportDirectoryAtom : public IdataAtom {
+public:
+  ImportDirectoryAtom(Context &ctx, StringRef loadName,
+                      const vector<COFFSharedLibraryAtom *> &sharedAtoms)
+      : IdataAtom(ctx.file, vector<uint8_t>(20, 0)) {
+    addRelocations(ctx, loadName, sharedAtoms);
+    ctx.importDirectories.push_back(this);
+  }
+
+private:
+  void addRelocations(Context &ctx, StringRef loadName,
+                      const vector<COFFSharedLibraryAtom *> &sharedAtoms) {
+    size_t lookupEnd = ctx.importLookupTables.size();
+    size_t addressEnd = ctx.importAddressTables.size();
+
+    // Create parallel arrays. The contents of the two are initially the
+    // same. The PE/COFF loader overwrites the import address tables with the
+    // pointers to the referenced items after loading the executable into
+    // memory.
+    addImportTableAtoms(ctx, sharedAtoms, false, ctx.importLookupTables);
+    addImportTableAtoms(ctx, sharedAtoms, true, ctx.importAddressTables);
+
+    addDir32NBReloc(this, ctx.importLookupTables[lookupEnd],
+                    offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA));
+    addDir32NBReloc(this, ctx.importAddressTables[addressEnd],
+                    offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA));
+    addDir32NBReloc(this, new (_alloc) DLLNameAtom(ctx, loadName),
+                    offsetof(ImportDirectoryTableEntry, NameRVA));
+  }
+
+  // Creates atoms for an import lookup table. The import lookup table is an
+  // array of pointers to hint/name atoms. The array needs to be terminated with
+  // the NULL entry.
+  void addImportTableAtoms(Context &ctx,
+                           const vector<COFFSharedLibraryAtom *> &sharedAtoms,
+                           bool shouldAddReference,
+                           vector<ImportTableEntryAtom *> &ret) const {
+    for (COFFSharedLibraryAtom *shared : sharedAtoms) {
+      HintNameAtom *hintName = createHintNameAtom(ctx, shared);
+      ImportTableEntryAtom *entry = new (_alloc) ImportTableEntryAtom(ctx);
+      addDir32NBReloc(entry, hintName, 0);
+      ret.push_back(entry);
+      if (shouldAddReference)
+        shared->setImportTableEntry(entry);
+    }
+    // Add the NULL entry.
+    ret.push_back(new (_alloc) ImportTableEntryAtom(ctx));
+  }
+
+  HintNameAtom *createHintNameAtom(
+      Context &ctx, const COFFSharedLibraryAtom *atom) const {
+    return new (_alloc) HintNameAtom(ctx, atom->hint(), atom->unmangledName());
+  }
+
+  mutable llvm::BumpPtrAllocator _alloc;
+};
+
+/// The last NULL entry in the import directory.
+class NullImportDirectoryAtom : public IdataAtom {
+public:
+  explicit NullImportDirectoryAtom(Context &ctx)
+      : IdataAtom(ctx.file, vector<uint8_t>(20, 0)) {
+    ctx.importDirectories.push_back(this);
+  }
+};
+
+} // anonymous namespace
+
+class IdataPass : public lld::Pass {
+public:
+  virtual void perform(MutableFile &file) {
+    if (file.sharedLibrary().size() == 0)
+      return;
+
+    Context ctx(file);
+    map<StringRef, vector<COFFSharedLibraryAtom *>> sharedAtoms =
+        groupByLoadName(file);
+    for (auto i : sharedAtoms) {
+      StringRef loadName = i.first;
+      vector<COFFSharedLibraryAtom *> &atoms = i.second;
+      createImportDirectory(ctx, loadName, atoms);
+    }
+    new (_alloc) NullImportDirectoryAtom(ctx);
+    connectAtoms(ctx);
+    createDataDirectoryAtoms(ctx);
+    replaceSharedLibraryAtoms(ctx);
+  }
+
+private:
+  map<StringRef, vector<COFFSharedLibraryAtom *>>
+  groupByLoadName(MutableFile &file) {
+    map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms;
+    for (const SharedLibraryAtom *atom : file.sharedLibrary())
+      uniqueAtoms[atom->name()] = (COFFSharedLibraryAtom *)atom;
+
+    map<StringRef, vector<COFFSharedLibraryAtom *>> ret;
+    for (auto i : uniqueAtoms) {
+      COFFSharedLibraryAtom *atom = i.second;
+      ret[atom->loadName()].push_back(atom);
+    }
+    return std::move(ret);
+  }
+
+  void
+  createImportDirectory(Context &ctx, StringRef loadName,
+                        vector<COFFSharedLibraryAtom *> &dllAtoms) {
+    new (_alloc) ImportDirectoryAtom(ctx, loadName, dllAtoms);
+  }
+
+  void connectAtoms(Context &ctx) {
+    coff::connectAtomsWithLayoutEdge(ctx.importDirectories);
+    coff::connectAtomsWithLayoutEdge(ctx.importLookupTables);
+    coff::connectAtomsWithLayoutEdge(ctx.importAddressTables);
+    coff::connectAtomsWithLayoutEdge(ctx.hintNameAtoms);
+    coff::connectAtomsWithLayoutEdge(ctx.dllNameAtoms);
+  }
+
+  /// The addresses of the import dirctory and the import address table needs to
+  /// be set to the COFF Optional Data Directory header. A COFFDataDirectoryAtom
+  /// represents an entry in the data directory header. We create atoms of class
+  /// COFFDataDirectoryAtom and set relocations to them, so that the address
+  /// will be set by the writer.
+  void createDataDirectoryAtoms(Context &ctx) {
+    auto *dir = new (_alloc) coff::COFFDataDirectoryAtom(ctx.file, 1);
+    addDir32NBReloc(dir, ctx.importDirectories[0], 0);
+    ctx.file.addAtom(*dir);
+
+    auto *iat = new (_alloc) coff::COFFDataDirectoryAtom(ctx.file, 12);
+    addDir32NBReloc(iat, ctx.importAddressTables[0], 0);
+    ctx.file.addAtom(*iat);
+  }
+
+  /// Transforms a reference to a COFFSharedLibraryAtom to a real reference.
+  void replaceSharedLibraryAtoms(Context &ctx) {
+    for (const DefinedAtom *atom : ctx.file.defined()) {
+      for (const Reference *ref : *atom) {
+        const Atom *target = ref->target();
+        auto *sharedAtom = dyn_cast<SharedLibraryAtom>(target);
+        if (!sharedAtom)
+          continue;
+        auto *coffSharedAtom = (COFFSharedLibraryAtom *)sharedAtom;
+        const DefinedAtom *entry = coffSharedAtom->getImportTableEntry();
+        const_cast<Reference *>(ref)->setTarget(entry);
+      }
+    }
+  }
+
+  llvm::BumpPtrAllocator _alloc;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
index 94bf110..4b18234 100644 (file)
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "GroupedSectionsPass.h"
+#include "IdataPass.h"
 
 #include "lld/Core/PassManager.h"
 #include "lld/Passes/LayoutPass.h"
@@ -59,6 +60,7 @@ PECOFFTargetInfo::stringFromRelocKind(Reference::Kind kind) const {
 
 void PECOFFTargetInfo::addPasses(PassManager &pm) const {
   pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass()));
+  pm.add(std::unique_ptr<Pass>(new pecoff::IdataPass()));
   pm.add(std::unique_ptr<Pass>(new LayoutPass()));
 }
 
index 173f72b..134abfa 100644 (file)
@@ -135,7 +135,8 @@ namespace {
 class FuncAtom : public COFFLinkerInternalAtom {
 public:
   FuncAtom(const File &file, StringRef symbolName)
-      : COFFLinkerInternalAtom(file, &rawContent, symbolName) {}
+      : COFFLinkerInternalAtom(file, std::vector<uint8_t>(rawContent),
+                               symbolName) {}
 
   virtual uint64_t ordinal() const { return 0; }
   virtual Scope scope() const { return scopeGlobal; }
index 0c6ddc9..8be3452 100644 (file)
@@ -64,7 +64,8 @@ class Chunk {
 public:
   enum Kind {
     kindHeader,
-    kindSection
+    kindSection,
+    kindDataDirectory
   };
 
   explicit Chunk(Kind kind) : _kind(kind), _size(0), _align(1) {}
@@ -243,43 +244,6 @@ private:
   llvm::object::pe32_header _peHeader;
 };
 
-/// A DataDirectoryChunk represents data directory entries that follows the PE
-/// header in the output file. An entry consists of an 8 byte field that
-/// indicates a relative virtual address (the starting address of the entry data
-/// in memory) and 8 byte entry data size.
-class DataDirectoryChunk : public HeaderChunk {
-public:
-  DataDirectoryChunk() : HeaderChunk() {
-    _size = sizeof(_dirs);
-    std::memset(_dirs, 0, sizeof(_dirs));
-  }
-
-  // Set the import table address and size. The import table is usually in
-  // .idata section, but because .idata section can be merged with other section
-  // such as .rdata, the given address can be in any section.
-  void setImportTableDirectoryRva(uint32_t rva, uint32_t size) {
-    _dirs[1].RelativeVirtualAddress = rva;
-    _dirs[1].Size = size;
-  }
-
-  // Set the address and size of the import address table (IAT). This is
-  // redundant information because the import table contains the file offset of
-  // the IAT. Although it's redundant, it needs to be set properly, otherwise
-  // the loader refuses the executable.
-  void setImportAddressTableRva(uint32_t rva, uint32_t size) {
-    _dirs[12].RelativeVirtualAddress = rva;
-    _dirs[12].Size = size;
-  }
-
-  virtual void write(uint8_t *fileBuffer) {
-    fileBuffer += fileOffset();
-    std::memcpy(fileBuffer, &_dirs, sizeof(_dirs));
-  }
-
-private:
-  llvm::object::data_directory _dirs[16];
-};
-
 /// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
 /// format, which is a list of section headers.
 class SectionHeaderTableChunk : public HeaderChunk {
@@ -363,11 +327,51 @@ public:
       layout->_virtualAddr += rva;
   }
 
+  static bool classof(const Chunk *c) {
+    Kind kind = c->getKind();
+    return kind == kindSection || kind == kindDataDirectory;
+  }
+
 protected:
   AtomChunk(Kind kind) : Chunk(kind) {}
   std::vector<AtomLayout *> _atomLayouts;
 };
 
+/// A DataDirectoryChunk represents data directory entries that follows the PE
+/// header in the output file. An entry consists of an 8 byte field that
+/// indicates a relative virtual address (the starting address of the entry data
+/// in memory) and 8 byte entry data size.
+class DataDirectoryChunk : public AtomChunk {
+public:
+  DataDirectoryChunk(const File &linkedFile)
+      : AtomChunk(kindDataDirectory) {
+    // Extract atoms from the linked file and append them to this section.
+    for (const DefinedAtom *atom : linkedFile.defined()) {
+      if (atom->contentType() == DefinedAtom::typeDataDirectoryEntry) {
+        uint64_t size = atom->ordinal() * sizeof(llvm::object::data_directory);
+        _atomLayouts.push_back(new (_alloc) AtomLayout(atom, size, size));
+      }
+    }
+  }
+
+  virtual uint64_t size() const {
+    return sizeof(llvm::object::data_directory) * 16;
+  }
+
+  virtual void write(uint8_t *fileBuffer) {
+    fileBuffer += fileOffset();
+    for (const AtomLayout *layout : _atomLayouts) {
+      if (!layout)
+        continue;
+      ArrayRef<uint8_t> content = static_cast<const DefinedAtom *>(layout->_atom)->rawContent();
+      std::memcpy(fileBuffer + layout->_fileOffset, content.data(), content.size());
+    }
+  }
+
+private:
+  mutable llvm::BumpPtrAllocator _alloc;
+};
+
 /// A SectionChunk represents a section containing atoms. It consists of a
 /// section header that to be written to PECOFF header and atoms which to be
 /// written to the raw data section.
@@ -453,13 +457,13 @@ private:
   }
 
   void appendAtom(const DefinedAtom *atom) {
-    auto *layout = new (_storage) AtomLayout(atom, _size, _size);
+    auto *layout = new (_alloc) AtomLayout(atom, _size, _size);
     _atomLayouts.push_back(layout);
     _size += atom->rawContent().size();
   }
 
   llvm::object::coff_section _sectionHeader;
-  mutable llvm::BumpPtrAllocator _storage;
+  mutable llvm::BumpPtrAllocator _alloc;
 };
 
 void SectionHeaderTableChunk::addSection(SectionChunk *chunk) {
@@ -545,10 +549,10 @@ private:
   void applyRelocations(uint8_t *bufferStart) {
     std::map<const Atom *, uint64_t> atomToVirtualAddr;
     for (auto &cp : _chunks)
-      if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp))
+      if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
         chunk->buildAtomToVirtualAddr(atomToVirtualAddr);
     for (auto &cp : _chunks)
-      if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp))
+      if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
         chunk->applyRelocations(bufferStart, atomToVirtualAddr);
   }
 
@@ -586,7 +590,7 @@ public:
     // Create file chunks and add them to the list.
     auto *dosStub = new DOSStubChunk();
     auto *peHeader = new PEHeaderChunk(_PECOFFTargetInfo);
-    auto *dataDirectory = new DataDirectoryChunk();
+    auto *dataDirectory = new DataDirectoryChunk(linkedFile);
     auto *sectionTable = new SectionHeaderTableChunk();
     auto *text = new TextSectionChunk(linkedFile);
     auto *rdata = new RDataSectionChunk(linkedFile);
diff --git a/lld/test/pecoff/Inputs/dynamic.dll b/lld/test/pecoff/Inputs/dynamic.dll
deleted file mode 100644 (file)
index c9e76e7..0000000
Binary files a/lld/test/pecoff/Inputs/dynamic.dll and /dev/null differ
diff --git a/lld/test/pecoff/Inputs/dynamic.lib b/lld/test/pecoff/Inputs/dynamic.lib
deleted file mode 100644 (file)
index 52d2a23..0000000
Binary files a/lld/test/pecoff/Inputs/dynamic.lib and /dev/null differ
index 8509e85..b118490 100644 (file)
@@ -6,7 +6,7 @@ sections:
   - Name:            .text
     Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
     Alignment:       4
-    SectionData:     ""
+    SectionData:     90
   - Name:            .data
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
     Alignment:       4
@@ -22,7 +22,7 @@ sections:
   - Name:            ".debug$S"
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
     Alignment:       1
-    SectionData:     04000000F1000000670000002C000111000000005A3A5C67726F7570656473656374696F6E735C73656374696F6E2D67726F7570732E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C6572000000
+    SectionData:     04000000F1000000590000001E000111000000005A3A5C67726F757065642D73656374696F6E732E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C65720000000000
   - Name:            .drectve
     Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
     Alignment:       2147483648
@@ -41,7 +41,7 @@ symbols:
     ComplexType:     IMAGE_SYM_DTYPE_NULL
     StorageClass:    IMAGE_SYM_CLASS_STATIC
     NumberOfAuxSymbols: 1
-    AuxiliaryData:   000000000000000000000000000000000000
+    AuxiliaryData:   010000000000000000000000000000000000
   - Name:            .data
     Value:           0
     SectionNumber:   2
@@ -66,14 +66,14 @@ symbols:
     StorageClass:    IMAGE_SYM_CLASS_STATIC
     NumberOfAuxSymbols: 1
     AuxiliaryData:   040000000000000000000000000000000000
-  - Name:            ."debug$S"
+  - Name:            ".debug$S"
     Value:           0
     SectionNumber:   5
     SimpleType:      IMAGE_SYM_TYPE_NULL
     ComplexType:     IMAGE_SYM_DTYPE_NULL
     StorageClass:    IMAGE_SYM_CLASS_STATIC
     NumberOfAuxSymbols: 1
-    AuxiliaryData:   740000000000000000000000000000000000
+    AuxiliaryData:   680000000000000000000000000000000000
   - Name:            _main
     Value:           0
     SectionNumber:   1
diff --git a/lld/test/pecoff/Inputs/vars-main.c b/lld/test/pecoff/Inputs/vars-main.c
new file mode 100644 (file)
index 0000000..ac72617
--- /dev/null
@@ -0,0 +1,6 @@
+__declspec(dllimport) int var;
+__declspec(dllimport) int fn(void);
+
+int main() {
+  return var + fn();
+}
diff --git a/lld/test/pecoff/Inputs/vars-main.obj.yaml b/lld/test/pecoff/Inputs/vars-main.obj.yaml
new file mode 100644 (file)
index 0000000..6ca2dd0
--- /dev/null
@@ -0,0 +1,80 @@
+---
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            ".debug$S"
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     04000000F10000005500000017000111000000005A3A5C766172732D6D61696E2E6F626A003A003C11002200000700100000001B9D0100100000001B9D01004D6963726F736F667420285229204F7074696D697A696E6720436F6D70696C657200000000
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     558BECFF15000000008B0D0000000003015DC3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      __imp__fn
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  11
+        SymbolName:      __imp__var
+        Type:            IMAGE_REL_I386_DIR32
+symbols:
+  - Name:            "@comp.id"
+    Value:           11181339
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            "@feat.00"
+    Value:           1
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    NumberOfAuxSymbols: 1
+    AuxiliaryData:   2F0000000000000000000000000000000000
+  - Name:            ".debug$S"
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    NumberOfAuxSymbols: 1
+    AuxiliaryData:   640000000000000000000000000000000000
+  - Name:            .text
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    NumberOfAuxSymbols: 1
+    AuxiliaryData:   1300000002000000B8433CE4000000000000
+  - Name:            _main
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp__var
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp__fn
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/lld/test/pecoff/Inputs/vars.c b/lld/test/pecoff/Inputs/vars.c
new file mode 100644 (file)
index 0000000..6532824
--- /dev/null
@@ -0,0 +1,11 @@
+// cl.exe /c vars.c
+// link.exe /debug /nodefaultlib /entry:dllmain vars.obj
+__declspec(dllexport) int var = 3;
+
+__declspec(dllexport) int fn(void) {
+  return 4;
+}
+
+int dllmain() {
+  return 1;
+}
diff --git a/lld/test/pecoff/Inputs/vars.dll.yaml b/lld/test/pecoff/Inputs/vars.dll.yaml
new file mode 100644 (file)
index 0000000..cbeab6e
--- /dev/null
@@ -0,0 +1,19 @@
+---
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DLL ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       2147483648
+    SectionData:     558BECB8090000005DC3CCCCCCCCCCCC558BECB8010000005DC3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       2147483648
+    SectionData:     0000000041ADCC51000000003C2000000100000002000000020000002820000030200000382000000010000000300000452000004820000000000100766172732E646C6C00666E007661720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       2147483648
+    SectionData:     0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+symbols:
+...
diff --git a/lld/test/pecoff/Inputs/vars.lib b/lld/test/pecoff/Inputs/vars.lib
new file mode 100644 (file)
index 0000000..6ed368e
Binary files /dev/null and b/lld/test/pecoff/Inputs/vars.lib differ
index b15d8aa..62f5f36 100644 (file)
@@ -1,19 +1,17 @@
 # Verify that lld can handle .lib files. "main.obj" refers _val1 and
-# _val2 that are defined in "dynamic.lib".
+# _val2 that are defined in "vars.lib".
 #
-# RUN: yaml2obj %p/Inputs/main.obj.yaml > %t.obj
+# RUN: yaml2obj %p/Inputs/vars-main.obj.yaml > %t.obj
 #
 # RUN: lld -flavor link -out %t1 -subsystem console -- %t.obj \
-# RUN:   %p/Inputs/dynamic.lib && llvm-objdump -d %t1 | FileCheck %s
+# RUN:    %p/Inputs/vars.lib && llvm-objdump -d %t1 | FileCheck %s
 
 CHECK: Disassembly of section .text:
 CHECK: .text:
-CHECK:     1000:       a1 0c 10 40 00            movl    4198412, %eax
-CHECK:     1005:       03 05 14 10 40 00         addl    4198420, %eax
-CHECK:     100b:       c3                        ret
-CHECK:     100c:       ff 25 00 00 40 00         jmpl    *4194304
-CHECK:     1012:       90                        nop
-CHECK:     1013:       90                        nop
-CHECK:     1014:       ff 25 00 00 40 00         jmpl    *4194304
-CHECK:     101a:       90                        nop
-CHECK:     101b:       90                        nop
+CHECK:     1000:       55                    pushl   %ebp
+CHECK:     1001:       8b ec                 movl    %esp, %ebp
+CHECK:     1003:       ff 15 4c 20 40 00     calll   *4202572
+CHECK:     1009:       8b 0d 50 20 40 00     movl    4202576, %ecx
+CHECK:     100f:       03 01                 addl    (%ecx), %eax
+CHECK:     1011:       5d                    popl    %ebp
+CHECK:     1012:       c3                    ret