ExecutionEngine: Preliminary support for dynamically loadable coff objects
authorDavid Majnemer <david.majnemer@gmail.com>
Sat, 7 Mar 2015 20:21:27 +0000 (20:21 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sat, 7 Mar 2015 20:21:27 +0000 (20:21 +0000)
Provide basic support for dynamically loadable coff objects. Only handles a subset of x64 currently.

Patch by Andy Ayers!

Differential Revision: http://reviews.llvm.org/D7793

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231574 91177308-0d34-0410-b5e6-96231b3b80d8

lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt
lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.cpp [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h [new file with mode: 0644]
lib/Object/COFFObjectFile.cpp
test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64 [new file with mode: 0644]

index 12bbcc61db7eaeadfa063c4e19dc8c1ae7b58aae..3d313a1cc86bab96390668bc62c57243d47fac21 100644 (file)
@@ -2,6 +2,8 @@ add_llvm_library(LLVMRuntimeDyld
   RTDyldMemoryManager.cpp
   RuntimeDyld.cpp
   RuntimeDyldChecker.cpp
+  RuntimeDyldCOFF.cpp
   RuntimeDyldELF.cpp
   RuntimeDyldMachO.cpp
+  Targets/RuntimeDyldCOFFX86_64.cpp
   )
index 54f1a1c0cc2d35aef3da97ead73871bb1390f993..0560a1b6127df6a3cf18807c760fa5723e664128 100644 (file)
 
 #include "llvm/ExecutionEngine/RuntimeDyld.h"
 #include "RuntimeDyldCheckerImpl.h"
+#include "RuntimeDyldCOFF.h"
 #include "RuntimeDyldELF.h"
 #include "RuntimeDyldImpl.h"
 #include "RuntimeDyldMachO.h"
 #include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/COFF.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/MutexGuard.h"
 
@@ -264,6 +266,20 @@ static bool isRequiredForExecution(const SectionRef &Section) {
   const ObjectFile *Obj = Section.getObject();
   if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj))
     return ELFObj->getSectionFlags(Section) & ELF::SHF_ALLOC;
+  if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) {
+    const coff_section *CoffSection = COFFObj->getCOFFSection(Section);
+    // Avoid loading zero-sized COFF sections.
+    // In PE files, VirtualSize gives the section size, and SizeOfRawData
+    // may be zero for sections with content. In Obj files, SizeOfRawData 
+    // gives the section size, and VirtualSize is always zero. Hence
+    // the need to check for both cases below.
+    bool HasContent = (CoffSection->VirtualSize > 0) 
+      || (CoffSection->SizeOfRawData > 0);
+    bool IsDiscardable = CoffSection->Characteristics &
+      (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO);
+    return HasContent && !IsDiscardable;
+  }
+  
   assert(isa<MachOObjectFile>(Obj));
   return true;
  }
@@ -273,6 +289,15 @@ static bool isReadOnlyData(const SectionRef &Section) {
   if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj))
     return !(ELFObj->getSectionFlags(Section) &
              (ELF::SHF_WRITE | ELF::SHF_EXECINSTR));
+  if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj))
+    return ((COFFObj->getCOFFSection(Section)->Characteristics &
+             (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
+             | COFF::IMAGE_SCN_MEM_READ
+             | COFF::IMAGE_SCN_MEM_WRITE))
+             ==
+             (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
+             | COFF::IMAGE_SCN_MEM_READ));
+
   assert(isa<MachOObjectFile>(Obj));
   return false;
 }
@@ -281,6 +306,9 @@ static bool isZeroInit(const SectionRef &Section) {
   const ObjectFile *Obj = Section.getObject();
   if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj))
     return ELFObj->getSectionType(Section) == ELF::SHT_NOBITS;
+  if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj))
+    return COFFObj->getCOFFSection(Section)->Characteristics &
+            COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
 
   auto *MachO = cast<MachOObjectFile>(Obj);
   unsigned SectionType = MachO->getSectionType(Section);
@@ -512,7 +540,6 @@ unsigned RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
                                       const SectionRef &Section, bool IsCode) {
 
   StringRef data;
-  Check(Section.getContents(data));
   uint64_t Alignment64 = Section.getAlignment();
 
   unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
@@ -542,6 +569,7 @@ unsigned RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
   // Some sections, such as debug info, don't need to be loaded for execution.
   // Leave those where they are.
   if (IsRequired) {
+    Check(Section.getContents(data));
     Allocate = DataSize + PaddingSize + StubBufSize;
     Addr = IsCode ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID,
                                                 Name)
@@ -816,6 +844,15 @@ RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) {
 
 RuntimeDyld::~RuntimeDyld() {}
 
+static std::unique_ptr<RuntimeDyldCOFF>
+createRuntimeDyldCOFF(Triple::ArchType Arch, RTDyldMemoryManager *MM,
+                      bool ProcessAllSections, RuntimeDyldCheckerImpl *Checker) {
+  std::unique_ptr<RuntimeDyldCOFF> Dyld(RuntimeDyldCOFF::create(Arch, MM));
+  Dyld->setProcessAllSections(ProcessAllSections);
+  Dyld->setRuntimeDyldChecker(Checker);
+  return Dyld;
+}
+
 static std::unique_ptr<RuntimeDyldELF>
 createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections,
                      RuntimeDyldCheckerImpl *Checker) {
@@ -843,6 +880,10 @@ RuntimeDyld::loadObject(const ObjectFile &Obj) {
       Dyld = createRuntimeDyldMachO(
                static_cast<Triple::ArchType>(Obj.getArch()), MM,
                ProcessAllSections, Checker);
+    else if (Obj.isCOFF())
+      Dyld = createRuntimeDyldCOFF(
+               static_cast<Triple::ArchType>(Obj.getArch()), MM,
+               ProcessAllSections, Checker);
     else
       report_fatal_error("Incompatible object format!");
   }
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
new file mode 100644 (file)
index 0000000..4791f87
--- /dev/null
@@ -0,0 +1,85 @@
+//===-- RuntimeDyldCOFF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of COFF support for the MC-JIT runtime dynamic linker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RuntimeDyldCOFF.h"
+#include "Targets/RuntimeDyldCOFFX86_64.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Object/ObjectFile.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+#define DEBUG_TYPE "dyld"
+
+namespace {
+
+class LoadedCOFFObjectInfo : public RuntimeDyld::LoadedObjectInfo {
+public:
+  LoadedCOFFObjectInfo(RuntimeDyldImpl &RTDyld, unsigned BeginIdx,
+                       unsigned EndIdx)
+      : RuntimeDyld::LoadedObjectInfo(RTDyld, BeginIdx, EndIdx) {}
+
+  OwningBinary<ObjectFile>
+  getObjectForDebug(const ObjectFile &Obj) const override {
+    return OwningBinary<ObjectFile>();
+  }
+};
+}
+
+namespace llvm {
+
+std::unique_ptr<RuntimeDyldCOFF>
+llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch, RTDyldMemoryManager *MM) {
+  switch (Arch) {
+  default:
+    llvm_unreachable("Unsupported target for RuntimeDyldCOFF.");
+    break;
+  case Triple::x86_64:
+    return make_unique<RuntimeDyldCOFFX86_64>(MM);
+  }
+}
+
+std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
+RuntimeDyldCOFF::loadObject(const object::ObjectFile &O) {
+  unsigned SectionStartIdx, SectionEndIdx;
+  std::tie(SectionStartIdx, SectionEndIdx) = loadObjectImpl(O);
+  return llvm::make_unique<LoadedCOFFObjectInfo>(*this, SectionStartIdx,
+                                                 SectionEndIdx);
+}
+
+uint64_t RuntimeDyldCOFF::getSymbolOffset(const SymbolRef &Sym) {
+  uint64_t Address;
+  if (std::error_code EC = Sym.getAddress(Address))
+    return UnknownAddressOrSize;
+
+  if (Address == UnknownAddressOrSize)
+    return UnknownAddressOrSize;
+
+  const ObjectFile *Obj = Sym.getObject();
+  section_iterator SecI(Obj->section_end());
+  if (std::error_code EC = Sym.getSection(SecI))
+    return UnknownAddressOrSize;
+
+  if (SecI == Obj->section_end())
+    return UnknownAddressOrSize;
+
+  uint64_t SectionAddress = SecI->getAddress();
+  return Address - SectionAddress;
+}
+
+bool RuntimeDyldCOFF::isCompatibleFile(const object::ObjectFile &Obj) const {
+  return Obj.isCOFF();
+}
+
+} // namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h
new file mode 100644 (file)
index 0000000..681a3e5
--- /dev/null
@@ -0,0 +1,46 @@
+//===-- RuntimeDyldCOFF.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// COFF support for MC-JIT runtime dynamic linker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_RUNTIME_DYLD_COFF_H
+#define LLVM_RUNTIME_DYLD_COFF_H
+
+#include "RuntimeDyldImpl.h"
+#include "llvm/ADT/DenseMap.h"
+
+#define DEBUG_TYPE "dyld"
+
+using namespace llvm;
+
+namespace llvm {
+
+// Common base class for COFF dynamic linker support.
+// Concrete subclasses for each target can be found in ./Targets.
+class RuntimeDyldCOFF : public RuntimeDyldImpl {
+
+public:
+  std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
+  loadObject(const object::ObjectFile &Obj) override;
+  bool isCompatibleFile(const object::ObjectFile &Obj) const override;
+  static std::unique_ptr<RuntimeDyldCOFF> create(Triple::ArchType Arch,
+                                                 RTDyldMemoryManager *MM);
+
+protected:
+  RuntimeDyldCOFF(RTDyldMemoryManager *MM) : RuntimeDyldImpl(MM) {}
+  uint64_t getSymbolOffset(const SymbolRef &Sym);
+};
+
+} // end namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif
index b4414b08c4806a53805ca4e614803904c1d8519d..71260d02f950e686ddd465a950c25d210e42cd3c 100644 (file)
 using namespace llvm;
 
 namespace llvm {
-namespace {
-// Helper for extensive error checking in debug builds.
-std::error_code Check(std::error_code Err) {
-  if (Err) {
-    report_fatal_error(Err.message());
-  }
-  return Err;
-}
-
-} // end anonymous namespace
 
 class RuntimeDyldELF : public RuntimeDyldImpl {
 
index f37a9a768a2e5de8d71c23c8bf003ed1343393ac..210ee47eb7495d4d3cab34c6fc6ef54860012233 100644 (file)
@@ -36,6 +36,16 @@ using namespace llvm::object;
 
 namespace llvm {
 
+namespace {
+  // Helper for extensive error checking in debug builds.
+  std::error_code Check(std::error_code Err) {
+    if (Err) {
+      report_fatal_error(Err.message());
+    }
+    return Err;
+  }
+} // end anonymous namespace
+
 class Twine;
 
 /// SectionEntry - represents a section emitted into memory by the dynamic
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.cpp b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.cpp
new file mode 100644 (file)
index 0000000..342eb13
--- /dev/null
@@ -0,0 +1,189 @@
+//===-- RuntimeDyldCOFFX86_64.cpp - COFF/X86_64 specific code ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// COFF x86_x64 support for MC-JIT runtime dynamic linker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RuntimeDyldCOFFX86_64.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+void RuntimeDyldCOFFX86_64::registerEHFrames() {
+  if (!MemMgr)
+    return;
+  for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
+    uint8_t *EHFrameAddr = Sections[EHFrameSID].Address;
+    uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress;
+    size_t EHFrameSize = Sections[EHFrameSID].Size;
+    MemMgr->registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
+    RegisteredEHFrameSections.push_back(EHFrameSID);
+  }
+  UnregisteredEHFrameSections.clear();
+}
+
+void RuntimeDyldCOFFX86_64::deregisterEHFrames() {
+  // Stub
+}
+
+// The target location for the relocation is described by RE.SectionID and
+// RE.Offset.  RE.SectionID can be used to find the SectionEntry.  Each
+// SectionEntry has three members describing its location.
+// SectionEntry::Address is the address at which the section has been loaded
+// into memory in the current (host) process.  SectionEntry::LoadAddress is the
+// address that the section will have in the target process.
+// SectionEntry::ObjAddress is the address of the bits for this section in the
+// original emitted object image (also in the current address space).
+//
+// Relocations will be applied as if the section were loaded at
+// SectionEntry::LoadAddress, but they will be applied at an address based
+// on SectionEntry::Address.  SectionEntry::ObjAddress will be used to refer to
+// Target memory contents if they are required for value calculations.
+//
+// The Value parameter here is the load address of the symbol for the
+// relocation to be applied.  For relocations which refer to symbols in the
+// current object Value will be the LoadAddress of the section in which
+// the symbol resides (RE.Addend provides additional information about the
+// symbol location).  For external symbols, Value will be the address of the
+// symbol in the target address space.
+void RuntimeDyldCOFFX86_64::resolveRelocation(const RelocationEntry &RE,
+                                              uint64_t Value) {
+  const SectionEntry &Section = Sections[RE.SectionID];
+  uint8_t *Target = Section.Address + RE.Offset;
+
+  switch (RE.RelType) {
+
+  case COFF::IMAGE_REL_AMD64_REL32:
+  case COFF::IMAGE_REL_AMD64_REL32_1:
+  case COFF::IMAGE_REL_AMD64_REL32_2:
+  case COFF::IMAGE_REL_AMD64_REL32_3:
+  case COFF::IMAGE_REL_AMD64_REL32_4:
+  case COFF::IMAGE_REL_AMD64_REL32_5: {
+    uint32_t *TargetAddress = (uint32_t *)Target;
+    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+    // Delta is the distance from the start of the reloc to the end of the
+    // instruction with the reloc.
+    uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32);
+    Value -= FinalAddress + Delta;
+    uint64_t Result = Value + RE.Addend;
+    assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow");
+    assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow");
+    *TargetAddress = Result;
+    break;
+  }
+
+  case COFF::IMAGE_REL_AMD64_ADDR32NB: {
+    // Note ADDR32NB requires a well-established notion of
+    // image base. This address must be less than or equal
+    // to every section's load address, and all sections must be
+    // within a 32 bit offset from the base.
+    //
+    // For now we just set these to zero.
+    uint32_t *TargetAddress = (uint32_t *)Target;
+    *TargetAddress = 0;
+    break;
+  }
+
+  case COFF::IMAGE_REL_AMD64_ADDR64: {
+    uint64_t *TargetAddress = (uint64_t *)Target;
+    *TargetAddress = Value + RE.Addend;
+    break;
+  }
+
+  default:
+    llvm_unreachable("Relocation type not implemented yet!");
+    break;
+  }
+}
+
+relocation_iterator RuntimeDyldCOFFX86_64::processRelocationRef(
+    unsigned SectionID, relocation_iterator RelI, const ObjectFile &Obj,
+    ObjSectionToIDMap &ObjSectionToID, StubMap &Stubs) {
+
+  // Find the symbol referred to in the relocation, and
+  // get its section and offset.
+  //
+  // Insist for now that all symbols be resolvable within
+  // the scope of this object file.
+  symbol_iterator Symbol = RelI->getSymbol();
+  if (Symbol == Obj.symbol_end())
+    report_fatal_error("Unknown symbol in relocation");
+  unsigned TargetSectionID = 0;
+  uint64_t TargetOffset = UnknownAddressOrSize;
+  const COFFObjectFile *COFFObj = cast<COFFObjectFile>(&Obj);
+  section_iterator SecI(Obj.section_end());
+  Symbol->getSection(SecI);
+  if (SecI == Obj.section_end())
+    report_fatal_error("Unknown section in relocation");
+  bool IsCode = SecI->isText();
+  TargetSectionID = findOrEmitSection(Obj, *SecI, IsCode, ObjSectionToID);
+  TargetOffset = getSymbolOffset(*Symbol);
+
+  // Determine the Addend used to adjust the relocation value.
+  uint64_t RelType;
+  Check(RelI->getType(RelType));
+  uint64_t Offset;
+  Check(RelI->getOffset(Offset));
+  uint64_t Addend = 0;
+  SectionEntry &Section = Sections[SectionID];
+  uintptr_t ObjTarget = Section.ObjAddress + Offset;
+
+  switch (RelType) {
+
+  case COFF::IMAGE_REL_AMD64_REL32:
+  case COFF::IMAGE_REL_AMD64_REL32_1:
+  case COFF::IMAGE_REL_AMD64_REL32_2:
+  case COFF::IMAGE_REL_AMD64_REL32_3:
+  case COFF::IMAGE_REL_AMD64_REL32_4:
+  case COFF::IMAGE_REL_AMD64_REL32_5:
+  case COFF::IMAGE_REL_AMD64_ADDR32NB: {
+    uint32_t *Displacement = (uint32_t *)ObjTarget;
+    Addend = *Displacement;
+    break;
+  }
+
+  case COFF::IMAGE_REL_AMD64_ADDR64: {
+    uint64_t *Displacement = (uint64_t *)ObjTarget;
+    Addend = *Displacement;
+    break;
+  }
+
+  default:
+    break;
+  }
+
+  StringRef TargetName;
+  Symbol->getName(TargetName);
+  DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
+               << " RelType: " << RelType << " TargetName: " << TargetName
+               << " Addend " << Addend << "\n");
+
+  RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
+  addRelocationForSection(RE, TargetSectionID);
+
+  return ++RelI;
+}
+
+void RuntimeDyldCOFFX86_64::finalizeLoad(const ObjectFile &Obj,
+                                         ObjSectionToIDMap &SectionMap) {
+  // Look for and record the EH frame section IDs.
+  for (const auto &SectionPair : SectionMap) {
+    const SectionRef &Section = SectionPair.first;
+    StringRef Name;
+    Check(Section.getName(Name));
+    // Note unwind info is split across .pdata and .xdata, so this
+    // may not be sufficiently general for all users.
+    if (Name == ".xdata") {
+      UnregisteredEHFrameSections.push_back(SectionPair.second);
+    }
+  }
+}
+}
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
new file mode 100644 (file)
index 0000000..fe5ae90
--- /dev/null
@@ -0,0 +1,60 @@
+//===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 specific code ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// COFF x86_x64 support for MC-JIT runtime dynamic linker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
+
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "../RuntimeDyldCOFF.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF {
+
+private:
+  // When a module is loaded we save the SectionID of the unwind
+  // sections in a table until we receive a request to register all
+  // unregisteredEH frame sections with the memory manager.
+  SmallVector<SID, 2> UnregisteredEHFrameSections;
+  SmallVector<SID, 2> RegisteredEHFrameSections;
+
+public:
+  RuntimeDyldCOFFX86_64(RTDyldMemoryManager *MM) : RuntimeDyldCOFF(MM) {}
+
+  unsigned getMaxStubSize() override {
+    return 6; // 2-byte jmp instruction + 32-bit relative address
+  }
+
+  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override;
+
+  relocation_iterator processRelocationRef(unsigned SectionID,
+                                           relocation_iterator RelI,
+                                           const ObjectFile &Obj,
+                                           ObjSectionToIDMap &ObjSectionToID,
+                                           StubMap &Stubs) override;
+
+  unsigned getStubAlignment() override { return 1; }
+  void registerEHFrames() override;
+  void deregisterEHFrames() override;
+  void finalizeLoad(const ObjectFile &Obj,
+                    ObjSectionToIDMap &SectionMap) override;
+};
+
+} // end namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif
index cde6fdc5f88b91a1c4c5de7e0ff8a3d761eaf5bd..ad278a449e8fc3e5b22eee6e9d88956444c5e829 100644 (file)
@@ -190,7 +190,9 @@ std::error_code COFFObjectFile::getSymbolType(DataRefImpl Ref,
     Result = SymbolRef::ST_Data;
   } else if (Symb.isFileRecord()) {
     Result = SymbolRef::ST_File;
-  } else if (SectionNumber == COFF::IMAGE_SYM_DEBUG) {
+  } else if (SectionNumber == COFF::IMAGE_SYM_DEBUG ||
+             Symb.isSectionDefinition()) {
+    // TODO: perhaps we need a new symbol type ST_Section.
     Result = SymbolRef::ST_Debug;
   } else if (!COFF::isReservedSectionNumber(SectionNumber)) {
     const coff_section *Section = nullptr;
@@ -359,12 +361,17 @@ bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
 
 bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
   const coff_section *Sec = toSec(Ref);
-  return Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+  const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+                            COFF::IMAGE_SCN_MEM_READ |
+                            COFF::IMAGE_SCN_MEM_WRITE;
+  return (Sec->Characteristics & BssFlags) == BssFlags;
 }
 
 bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
   const coff_section *Sec = toSec(Ref);
-  return Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+  // In COFF, a virtual section won't have any in-file 
+  // content, so the file pointer to the content will be zero.
+  return Sec->PointerToRawData == 0;
 }
 
 bool COFFObjectFile::sectionContainsSymbol(DataRefImpl SecRef,
diff --git a/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64 b/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64
new file mode 100644 (file)
index 0000000..7029cf4
--- /dev/null
@@ -0,0 +1,31 @@
+# RUN: llvm-mc -triple=x86_64-pc-win32 -filetype=obj -o %T/COFF_x86_64.o %s
+# RUN: llvm-rtdyld -triple=x86_64-pc-win32 -verify -check=%s %/T/COFF_x86_64.o
+               .text
+       .def     F;
+       .scl    2;
+       .type   32;
+       .endef
+       .globl  __real400921f9f01b866e
+       .section        .rdata,"dr",discard,__real400921f9f01b866e
+       .align  8
+__real400921f9f01b866e:
+       .quad   4614256650576692846     # double 3.1415899999999999
+       .text
+       .globl  F
+        .global inst1
+       .align  16, 0x90
+F:                                      # @F
+.Ltmp0:
+.seh_proc F
+# BB#0:                                 # %entry
+.Ltmp1:
+       .seh_endprologue
+# rtdyld-check: decode_operand(inst1, 4) = __real400921f9f01b866e - next_pc(inst1)
+inst1:
+       movsd   __real400921f9f01b866e(%rip), %xmm0 # xmm0 = mem[0],zero
+       retq
+.Leh_func_end0:
+.Ltmp2:
+       .seh_endproc
+
+