[MCJIT] Significantly refactor the RuntimeDyldMachO class.
authorLang Hames <lhames@gmail.com>
Thu, 17 Jul 2014 18:54:50 +0000 (18:54 +0000)
committerLang Hames <lhames@gmail.com>
Thu, 17 Jul 2014 18:54:50 +0000 (18:54 +0000)
The previous implementation of RuntimeDyldMachO mixed logic for all targets
within a single class, creating problems for readability, maintainability, and
performance. To address these issues, this patch strips the RuntimeDyldMachO
class down to just target-independent functionality, and moves all
target-specific functionality into target-specific subclasses RuntimeDyldMachO.

The new class hierarchy is as follows:

class RuntimeDyldMachO
Implemented in RuntimeDyldMachO.{h,cpp}
Contains logic that is completely independent of the target. This consists
mostly of MachO helper utilities which the derived classes use to get their
work done.

template <typename Impl>
class RuntimeDyldMachOCRTPBase<Impl> : public RuntimeDyldMachO
Implemented in RuntimeDyldMachO.h
Contains generic MachO algorithms/data structures that defer to the Impl class
for target-specific behaviors.

RuntimeDyldMachOARM : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM>
RuntimeDyldMachOARM64 : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM64>
RuntimeDyldMachOI386 : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386>
RuntimeDyldMachOX86_64 : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64>
Implemented in their respective *.h files in lib/ExecutionEngine/RuntimeDyld/MachOTargets
Each of these contains the relocation logic specific to their target architecture.

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

lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h [new file with mode: 0644]

index 9dfd167..f761c1d 100644 (file)
@@ -697,8 +697,9 @@ createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections) {
 }
 
 static std::unique_ptr<RuntimeDyldMachO>
-createRuntimeDyldMachO(RTDyldMemoryManager *MM, bool ProcessAllSections) {
-  std::unique_ptr<RuntimeDyldMachO> Dyld(new RuntimeDyldMachO(MM));
+createRuntimeDyldMachO(Triple::ArchType Arch, RTDyldMemoryManager *MM,
+                       bool ProcessAllSections) {
+  std::unique_ptr<RuntimeDyldMachO> Dyld(RuntimeDyldMachO::create(Arch, MM));
   Dyld->setProcessAllSections(ProcessAllSections);
   return Dyld;
 }
@@ -715,7 +716,9 @@ ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) {
   } else if (InputObject->isMachO()) {
     InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(std::move(InputObject)));
     if (!Dyld)
-      Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release();
+      Dyld = createRuntimeDyldMachO(
+                           static_cast<Triple::ArchType>(InputImage->getArch()),
+                           MM, ProcessAllSections).release();
   } else
     report_fatal_error("Incompatible object format!");
 
@@ -751,7 +754,9 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
   case sys::fs::file_magic::macho_dsym_companion:
     InputImage.reset(RuntimeDyldMachO::createObjectImage(InputBuffer));
     if (!Dyld)
-      Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release();
+      Dyld = createRuntimeDyldMachO(
+                           static_cast<Triple::ArchType>(InputImage->getArch()),
+                           MM, ProcessAllSections).release();
     break;
   case sys::fs::file_magic::unknown:
   case sys::fs::file_magic::bitcode:
index 0494ea2..d062b10 100644 (file)
 #include "RuntimeDyldMachO.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
+
+#include "Targets/RuntimeDyldMachOARM.h"
+#include "Targets/RuntimeDyldMachOAArch64.h"
+#include "Targets/RuntimeDyldMachOI386.h"
+#include "Targets/RuntimeDyldMachOX86_64.h"
+
 using namespace llvm;
 using namespace llvm::object;
 
@@ -21,6 +27,134 @@ using namespace llvm::object;
 
 namespace llvm {
 
+RelocationEntry
+RuntimeDyldMachO::getBasicRelocationEntry(unsigned SectionID,
+                                          ObjectImage &ObjImg,
+                                          const relocation_iterator &RI) const {
+
+  const MachOObjectFile &Obj =
+      static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+  MachO::any_relocation_info RelInfo =
+      Obj.getRelocation(RI->getRawDataRefImpl());
+
+  const SectionEntry &Section = Sections[SectionID];
+  bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo);
+  unsigned Size = Obj.getAnyRelocationLength(RelInfo);
+  uint64_t Offset;
+  RI->getOffset(Offset);
+  uint8_t *LocalAddress = Section.Address + Offset;
+  unsigned NumBytes = 1 << Size;
+  uint64_t Addend = 0;
+  memcpy(&Addend, LocalAddress, NumBytes);
+  uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
+
+  return RelocationEntry(SectionID, Offset, RelType, Addend, IsPCRel, Size);
+}
+
+RelocationValueRef RuntimeDyldMachO::getRelocationValueRef(
+    ObjectImage &ObjImg, const relocation_iterator &RI,
+    const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID,
+    const SymbolTableMap &Symbols) {
+
+  const MachOObjectFile &Obj =
+      static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+  MachO::any_relocation_info RelInfo =
+      Obj.getRelocation(RI->getRawDataRefImpl());
+  RelocationValueRef Value;
+
+  bool IsExternal = Obj.getPlainRelocationExternal(RelInfo);
+  if (IsExternal) {
+    symbol_iterator Symbol = RI->getSymbol();
+    StringRef TargetName;
+    Symbol->getName(TargetName);
+    SymbolTableMap::const_iterator SI = Symbols.find(TargetName.data());
+    if (SI != Symbols.end()) {
+      Value.SectionID = SI->second.first;
+      Value.Addend = SI->second.second + RE.Addend;
+    } else {
+      SI = GlobalSymbolTable.find(TargetName.data());
+      if (SI != GlobalSymbolTable.end()) {
+        Value.SectionID = SI->second.first;
+        Value.Addend = SI->second.second + RE.Addend;
+      } else {
+        Value.SymbolName = TargetName.data();
+        Value.Addend = RE.Addend;
+      }
+    }
+  } else {
+    SectionRef Sec = Obj.getRelocationSection(RelInfo);
+    bool IsCode = false;
+    Sec.isText(IsCode);
+    Value.SectionID = findOrEmitSection(ObjImg, Sec, IsCode, ObjSectionToID);
+    uint64_t Addr;
+    Sec.getAddress(Addr);
+    Value.Addend = RE.Addend - Addr;
+  }
+
+  return Value;
+}
+
+void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value,
+                                            ObjectImage &ObjImg,
+                                            const relocation_iterator &RI) {
+  const MachOObjectFile &Obj =
+      static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+  MachO::any_relocation_info RelInfo =
+      Obj.getRelocation(RI->getRawDataRefImpl());
+
+  bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo);
+  if (IsPCRel) {
+    uint64_t RelocAddr = 0;
+    RI->getAddress(RelocAddr);
+    unsigned RelocSize = Obj.getAnyRelocationLength(RelInfo);
+    Value.Addend += RelocAddr + (1 << RelocSize);
+  }
+}
+
+void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE,
+                                               uint64_t Value) const {
+  const SectionEntry &Section = Sections[RE.SectionID];
+  uint8_t *LocalAddress = Section.Address + RE.Offset;
+  uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+
+  dbgs() << "resolveRelocation Section: " << RE.SectionID
+         << " LocalAddress: " << format("%p", LocalAddress)
+         << " FinalAddress: " << format("%p", FinalAddress)
+         << " Value: " << format("%p", Value) << " Addend: " << RE.Addend
+         << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType
+         << " Size: " << (1 << RE.Size) << "\n";
+}
+
+bool RuntimeDyldMachO::writeBytesUnaligned(uint8_t *Addr, uint64_t Value,
+                                           unsigned Size) {
+  for (unsigned i = 0; i < Size; ++i) {
+    *Addr++ = (uint8_t)Value;
+    Value >>= 8;
+  }
+
+  return false;
+}
+
+bool
+RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const {
+  if (InputBuffer->getBufferSize() < 4)
+    return false;
+  StringRef Magic(InputBuffer->getBufferStart(), 4);
+  if (Magic == "\xFE\xED\xFA\xCE")
+    return true;
+  if (Magic == "\xCE\xFA\xED\xFE")
+    return true;
+  if (Magic == "\xFE\xED\xFA\xCF")
+    return true;
+  if (Magic == "\xCF\xFA\xED\xFE")
+    return true;
+  return false;
+}
+
+bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const {
+  return Obj->isMachO();
+}
+
 static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText,
                                  intptr_t DeltaForEH) {
   DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText
@@ -90,764 +224,17 @@ void RuntimeDyldMachO::registerEHFrames() {
   UnregisteredEHFrameSections.clear();
 }
 
-void RuntimeDyldMachO::finalizeLoad(ObjectImage &ObjImg,
-                                    ObjSectionToIDMap &SectionMap) {
-  unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID;
-  unsigned TextSID = RTDYLD_INVALID_SECTION_ID;
-  unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID;
-  ObjSectionToIDMap::iterator i, e;
-  for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) {
-    const SectionRef &Section = i->first;
-    StringRef Name;
-    Section.getName(Name);
-    if (Name == "__eh_frame")
-      EHFrameSID = i->second;
-    else if (Name == "__text")
-      TextSID = i->second;
-    else if (Name == "__gcc_except_tab")
-      ExceptTabSID = i->second;
-    else if (Name == "__jump_table")
-      populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
-                        Section, i->second);
-    else if (Name == "__pointers")
-      populatePointersSection(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
-                              Section, i->second);
-  }
-  UnregisteredEHFrameSections.push_back(
-      EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID));
-}
-
-// 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 RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE,
-                                         uint64_t Value) {
-  DEBUG (
-    const SectionEntry &Section = Sections[RE.SectionID];
-    uint8_t* LocalAddress = Section.Address + RE.Offset;
-    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-
-    dbgs() << "resolveRelocation Section: " << RE.SectionID
-           << " LocalAddress: " << format("%p", LocalAddress)
-           << " FinalAddress: " << format("%p", FinalAddress)
-           << " Value: " << format("%p", Value)
-           << " Addend: " << RE.Addend
-           << " isPCRel: " << RE.IsPCRel
-           << " MachoType: " << RE.RelType
-           << " Size: " << (1 << RE.Size) << "\n";
-  );
-
-  // This just dispatches to the proper target specific routine.
+std::unique_ptr<RuntimeDyldMachO>
+llvm::RuntimeDyldMachO::create(Triple::ArchType Arch, RTDyldMemoryManager *MM) {
   switch (Arch) {
   default:
-    llvm_unreachable("Unsupported CPU type!");
-  case Triple::x86_64:
-    resolveX86_64Relocation(RE, Value);
-    break;
-  case Triple::x86:
-    resolveI386Relocation(RE, Value);
-    break;
-  case Triple::arm: // Fall through.
-  case Triple::thumb:
-    resolveARMRelocation(RE, Value);
-    break;
-  case Triple::aarch64:
-  case Triple::arm64:
-    resolveAArch64Relocation(RE, Value);
-    break;
-  }
-}
-
-bool RuntimeDyldMachO::resolveI386Relocation(const RelocationEntry &RE,
-                                             uint64_t Value) {
-  const SectionEntry &Section = Sections[RE.SectionID];
-  uint8_t* LocalAddress = Section.Address + RE.Offset;
-
-  if (RE.IsPCRel) {
-    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-    Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
-  }
-
-  switch (RE.RelType) {
-    default:
-      llvm_unreachable("Invalid relocation type!");
-    case MachO::GENERIC_RELOC_VANILLA:
-      return applyRelocationValue(LocalAddress, Value + RE.Addend,
-                                  1 << RE.Size);
-    case MachO::GENERIC_RELOC_SECTDIFF:
-    case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
-      uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
-      uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
-      assert((Value == SectionABase || Value == SectionBBase) &&
-             "Unexpected SECTDIFF relocation value.");
-      Value = SectionABase - SectionBBase + RE.Addend;
-      return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
-    }
-    case MachO::GENERIC_RELOC_PB_LA_PTR:
-      return Error("Relocation type not implemented yet!");
-  }
-}
-
-bool RuntimeDyldMachO::resolveX86_64Relocation(const RelocationEntry &RE,
-                                               uint64_t Value) {
-  const SectionEntry &Section = Sections[RE.SectionID];
-  uint8_t* LocalAddress = Section.Address + RE.Offset;
-
-  // If the relocation is PC-relative, the value to be encoded is the
-  // pointer difference.
-  if (RE.IsPCRel) {
-    // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
-    // address. Is that expected? Only for branches, perhaps?
-    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-    Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
-  }
-
-  switch (RE.RelType) {
-  default:
-    llvm_unreachable("Invalid relocation type!");
-  case MachO::X86_64_RELOC_SIGNED_1:
-  case MachO::X86_64_RELOC_SIGNED_2:
-  case MachO::X86_64_RELOC_SIGNED_4:
-  case MachO::X86_64_RELOC_SIGNED:
-  case MachO::X86_64_RELOC_UNSIGNED:
-  case MachO::X86_64_RELOC_BRANCH:
-    return applyRelocationValue(LocalAddress, Value + RE.Addend, 1 << RE.Size);
-  case MachO::X86_64_RELOC_GOT_LOAD:
-  case MachO::X86_64_RELOC_GOT:
-  case MachO::X86_64_RELOC_SUBTRACTOR:
-  case MachO::X86_64_RELOC_TLV:
-    return Error("Relocation type not implemented yet!");
-  }
-}
-
-bool RuntimeDyldMachO::resolveARMRelocation(const RelocationEntry &RE,
-                                            uint64_t Value) {
-  const SectionEntry &Section = Sections[RE.SectionID];
-  uint8_t* LocalAddress = Section.Address + RE.Offset;
-
-  // If the relocation is PC-relative, the value to be encoded is the
-  // pointer difference.
-  if (RE.IsPCRel) {
-    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-    Value -= FinalAddress;
-    // ARM PCRel relocations have an effective-PC offset of two instructions
-    // (four bytes in Thumb mode, 8 bytes in ARM mode).
-    // FIXME: For now, assume ARM mode.
-    Value -= 8;
-  }
-
-  switch (RE.RelType) {
-  default:
-    llvm_unreachable("Invalid relocation type!");
-  case MachO::ARM_RELOC_VANILLA:
-    return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
-  case MachO::ARM_RELOC_BR24: {
-    // Mask the value into the target address. We know instructions are
-    // 32-bit aligned, so we can do it all at once.
-    uint32_t *p = (uint32_t *)LocalAddress;
-    // The low two bits of the value are not encoded.
-    Value >>= 2;
-    // Mask the value to 24 bits.
-    uint64_t FinalValue = Value & 0xffffff;
-    // Check for overflow.
-    if (Value != FinalValue)
-      return Error("ARM BR24 relocation out of range.");
-    // FIXME: If the destination is a Thumb function (and the instruction
-    // is a non-predicated BL instruction), we need to change it to a BLX
-    // instruction instead.
-
-    // Insert the value into the instruction.
-    *p = (*p & ~0xffffff) | FinalValue;
-    break;
-  }
-  case MachO::ARM_THUMB_RELOC_BR22:
-  case MachO::ARM_THUMB_32BIT_BRANCH:
-  case MachO::ARM_RELOC_HALF:
-  case MachO::ARM_RELOC_HALF_SECTDIFF:
-  case MachO::ARM_RELOC_PAIR:
-  case MachO::ARM_RELOC_SECTDIFF:
-  case MachO::ARM_RELOC_LOCAL_SECTDIFF:
-  case MachO::ARM_RELOC_PB_LA_PTR:
-    return Error("Relocation type not implemented yet!");
-  }
-  return false;
-}
-
-bool RuntimeDyldMachO::resolveAArch64Relocation(const RelocationEntry &RE,
-                                                uint64_t Value) {
-  const SectionEntry &Section = Sections[RE.SectionID];
-  uint8_t* LocalAddress = Section.Address + RE.Offset;
-
-  switch (RE.RelType) {
-  default:
-    llvm_unreachable("Invalid relocation type!");
-  case MachO::ARM64_RELOC_UNSIGNED: {
-    assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
-    // Mask in the target value a byte at a time (we don't have an alignment
-    // guarantee for the target address, so this is safest).
-    if (RE.Size < 2)
-      llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
-
-    applyRelocationValue(LocalAddress, Value + RE.Addend, 1 << RE.Size);
-    break;
-  }
-  case MachO::ARM64_RELOC_BRANCH26: {
-    assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
-    // Mask the value into the target address. We know instructions are
-    // 32-bit aligned, so we can do it all at once.
-    uint32_t *p = (uint32_t*)LocalAddress;
-    // Check if the addend is encoded in the instruction.
-    uint32_t EncodedAddend = *p & 0x03FFFFFF;
-    if (EncodedAddend != 0 ) {
-      if (RE.Addend == 0)
-        llvm_unreachable("branch26 instruction has embedded addend.");
-      else
-        llvm_unreachable("branch26 instruction has embedded addend and" \
-                         "ARM64_RELOC_ADDEND.");
-    }
-    // Check if branch is in range.
-    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-    uint64_t PCRelVal = Value - FinalAddress + RE.Addend;
-    assert(isInt<26>(PCRelVal) && "Branch target out of range!");
-    // Insert the value into the instruction.
-    *p = (*p & 0xFC000000) | ((uint32_t)(PCRelVal >> 2) & 0x03FFFFFF);
-    break;
-  }
-  case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
-  case MachO::ARM64_RELOC_PAGE21: {
-    assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
-    // Mask the value into the target address. We know instructions are
-    // 32-bit aligned, so we can do it all at once.
-    uint32_t *p = (uint32_t*)LocalAddress;
-    // Check if the addend is encoded in the instruction.
-    uint32_t EncodedAddend = ((*p & 0x60000000) >> 29) |
-                             ((*p & 0x01FFFFE0) >> 3);
-    if (EncodedAddend != 0) {
-      if (RE.Addend == 0)
-        llvm_unreachable("adrp instruction has embedded addend.");
-      else
-        llvm_unreachable("adrp instruction has embedded addend and" \
-                         "ARM64_RELOC_ADDEND.");
-    }
-    // Adjust for PC-relative relocation and offset.
-    uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-    uint64_t PCRelVal = ((Value + RE.Addend) & (-4096)) -
-                         (FinalAddress & (-4096));
-    // Check that the value fits into 21 bits (+ 12 lower bits).
-    assert(isInt<33>(PCRelVal) && "Invalid page reloc value!");
-    // Insert the value into the instruction.
-    uint32_t ImmLoValue = (uint32_t)(PCRelVal << 17) & 0x60000000;
-    uint32_t ImmHiValue = (uint32_t)(PCRelVal >>  9) & 0x00FFFFE0;
-    *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
-    break;
-  }
-  case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
-  case MachO::ARM64_RELOC_PAGEOFF12: {
-    assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
-    // Mask the value into the target address. We know instructions are
-    // 32-bit aligned, so we can do it all at once.
-    uint32_t *p = (uint32_t*)LocalAddress;
-    // Check if the addend is encoded in the instruction.
-    uint32_t EncodedAddend = *p & 0x003FFC00;
-    if (EncodedAddend != 0) {
-      if (RE.Addend == 0)
-        llvm_unreachable("adrp instruction has embedded addend.");
-      else
-        llvm_unreachable("adrp instruction has embedded addend and" \
-                         "ARM64_RELOC_ADDEND.");
-    }
-    // Add the offset from the symbol.
-    Value += RE.Addend;
-    // Mask out the page address and only use the lower 12 bits.
-    Value &= 0xFFF;
-    // Check which instruction we are updating to obtain the implicit shift
-    // factor from LDR/STR instructions.
-    if (*p & 0x08000000) {
-      uint32_t ImplicitShift = ((*p >> 30) & 0x3);
-      switch (ImplicitShift) {
-      case 0:
-        // Check if this a vector op.
-        if ((*p & 0x04800000) == 0x04800000) {
-          ImplicitShift = 4;
-          assert(((Value & 0xF) == 0) &&
-                 "128-bit LDR/STR not 16-byte aligned.");
-        }
-        break;
-      case 1:
-        assert(((Value & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
-      case 2:
-        assert(((Value & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
-      case 3:
-        assert(((Value & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
-      }
-      // Compensate for implicit shift.
-      Value >>= ImplicitShift;
-    }
-    // Insert the value into the instruction.
-    *p = (*p & 0xFFC003FF) | ((uint32_t)(Value << 10) & 0x003FFC00);
+    llvm_unreachable("Unsupported target for RuntimeDyldMachO.");
     break;
+  case Triple::arm: return make_unique<RuntimeDyldMachOARM>(MM);
+  case Triple::arm64: return make_unique<RuntimeDyldMachOAArch64>(MM);
+  case Triple::x86: return make_unique<RuntimeDyldMachOI386>(MM);
+  case Triple::x86_64: return make_unique<RuntimeDyldMachOX86_64>(MM);
   }
-  case MachO::ARM64_RELOC_SUBTRACTOR:
-  case MachO::ARM64_RELOC_POINTER_TO_GOT:
-  case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
-  case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
-    llvm_unreachable("Relocation type not implemented yet!");
-    return Error("Relocation type not implemented yet!");
-  case MachO::ARM64_RELOC_ADDEND:
-    llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by " \
-                     "processRelocationRef!");
-  }
-  return false;
-}
-
-void RuntimeDyldMachO::populateJumpTable(MachOObjectFile &Obj,
-                                         const SectionRef &JTSection,
-                                         unsigned JTSectionID) {
-  assert(!Obj.is64Bit() &&
-         "__jump_table section not supported in 64-bit MachO.");
-
-  MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
-  MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
-  uint32_t JTSectionSize = Sec32.size;
-  unsigned FirstIndirectSymbol = Sec32.reserved1;
-  unsigned JTEntrySize = Sec32.reserved2;
-  unsigned NumJTEntries = JTSectionSize / JTEntrySize;
-  uint8_t* JTSectionAddr = getSectionAddress(JTSectionID);
-  unsigned JTEntryOffset = 0;
-
-  assert((JTSectionSize % JTEntrySize) == 0 &&
-         "Jump-table section does not contain a whole number of stubs?");
-
-  for (unsigned i = 0; i < NumJTEntries; ++i) {
-    unsigned SymbolIndex =
-      Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
-    symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
-    StringRef IndirectSymbolName;
-    SI->getName(IndirectSymbolName);
-    uint8_t* JTEntryAddr = JTSectionAddr + JTEntryOffset;
-    createStubFunction(JTEntryAddr);
-    RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
-                       MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
-    addRelocationForSymbol(RE, IndirectSymbolName);
-    JTEntryOffset += JTEntrySize;
-  }
-}
-
-void RuntimeDyldMachO::populatePointersSection(MachOObjectFile &Obj,
-                                               const SectionRef &PTSection,
-                                               unsigned PTSectionID) {
-  assert(!Obj.is64Bit() &&
-         "__pointers section not supported in 64-bit MachO.");
-
-  MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
-  MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl());
-  uint32_t PTSectionSize = Sec32.size;
-  unsigned FirstIndirectSymbol = Sec32.reserved1;
-  const unsigned PTEntrySize = 4;
-  unsigned NumPTEntries = PTSectionSize / PTEntrySize;
-  unsigned PTEntryOffset = 0;
-
-  assert((PTSectionSize % PTEntrySize) == 0 &&
-         "Pointers section does not contain a whole number of stubs?");
-
-  DEBUG(dbgs() << "Populating __pointers, Section ID " << PTSectionID
-               << ", " << NumPTEntries << " entries, "
-               << PTEntrySize << " bytes each:\n");
-
-  for (unsigned i = 0; i < NumPTEntries; ++i) {
-    unsigned SymbolIndex =
-      Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
-    symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
-    StringRef IndirectSymbolName;
-    SI->getName(IndirectSymbolName);
-    DEBUG(dbgs() << "  " << IndirectSymbolName << ": index " << SymbolIndex
-          << ", PT offset: " << PTEntryOffset << "\n");
-    RelocationEntry RE(PTSectionID, PTEntryOffset,
-                       MachO::GENERIC_RELOC_VANILLA, 0, false, 2);
-    addRelocationForSymbol(RE, IndirectSymbolName);
-    PTEntryOffset += PTEntrySize;
-  }
-}
-
-
-section_iterator getSectionByAddress(const MachOObjectFile &Obj,
-                                     uint64_t Addr) {
-  section_iterator SI = Obj.section_begin();
-  section_iterator SE = Obj.section_end();
-
-  for (; SI != SE; ++SI) {
-    uint64_t SAddr, SSize;
-    SI->getAddress(SAddr);
-    SI->getSize(SSize);
-    if ((Addr >= SAddr) && (Addr < SAddr + SSize))
-      return SI;
-  }
-
-  return SE;
-}
-
-relocation_iterator RuntimeDyldMachO::processSECTDIFFRelocation(
-                                            unsigned SectionID,
-                                            relocation_iterator RelI,
-                                            ObjectImage &Obj,
-                                            ObjSectionToIDMap &ObjSectionToID) {
-  const MachOObjectFile *MachO =
-    static_cast<const MachOObjectFile*>(Obj.getObjectFile());
-  MachO::any_relocation_info RE =
-    MachO->getRelocation(RelI->getRawDataRefImpl());
-
-  SectionEntry &Section = Sections[SectionID];
-  uint32_t RelocType = MachO->getAnyRelocationType(RE);
-  bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
-  unsigned Size = MachO->getAnyRelocationLength(RE);
-  uint64_t Offset;
-  RelI->getOffset(Offset);
-  uint8_t *LocalAddress = Section.Address + Offset;
-  unsigned NumBytes = 1 << Size;
-  int64_t Addend = 0;
-  memcpy(&Addend, LocalAddress, NumBytes);
-
-  ++RelI;
-  MachO::any_relocation_info RE2 =
-    MachO->getRelocation(RelI->getRawDataRefImpl());
-
-  uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
-  section_iterator SAI = getSectionByAddress(*MachO, AddrA);
-  assert(SAI != MachO->section_end() && "Can't find section for address A");
-  uint64_t SectionABase;
-  SAI->getAddress(SectionABase);
-  uint64_t SectionAOffset = AddrA - SectionABase;
-  SectionRef SectionA = *SAI;
-  bool IsCode;
-  SectionA.isText(IsCode);
-  uint32_t SectionAID = findOrEmitSection(Obj, SectionA, IsCode,
-                                          ObjSectionToID);
-
-  uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
-  section_iterator SBI = getSectionByAddress(*MachO, AddrB);
-  assert(SBI != MachO->section_end() && "Can't find section for address B");
-  uint64_t SectionBBase;
-  SBI->getAddress(SectionBBase);
-  uint64_t SectionBOffset = AddrB - SectionBBase;
-  SectionRef SectionB = *SBI;
-  uint32_t SectionBID = findOrEmitSection(Obj, SectionB, IsCode,
-                                          ObjSectionToID);
-
-  if (Addend != AddrA - AddrB)
-    Error("Unexpected SECTDIFF relocation addend.");
-
-  DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
-               << ", Addend: " << Addend << ", SectionA ID: "
-               << SectionAID << ", SectionAOffset: " << SectionAOffset
-               << ", SectionB ID: " << SectionBID << ", SectionBOffset: "
-               << SectionBOffset << "\n");
-  RelocationEntry R(SectionID, Offset, RelocType, 0,
-                    SectionAID, SectionAOffset, SectionBID, SectionBOffset,
-                    IsPCRel, Size);
-
-  addRelocationForSection(R, SectionAID);
-  addRelocationForSection(R, SectionBID);
-
-  return ++RelI;
-}
-
-relocation_iterator RuntimeDyldMachO::processI386ScatteredVANILLA(
-                                            unsigned SectionID,
-                                            relocation_iterator RelI,
-                                            ObjectImage &Obj,
-                                            ObjSectionToIDMap &ObjSectionToID) {
-  const MachOObjectFile *MachO =
-    static_cast<const MachOObjectFile*>(Obj.getObjectFile());
-  MachO::any_relocation_info RE =
-    MachO->getRelocation(RelI->getRawDataRefImpl());
-
-  SectionEntry &Section = Sections[SectionID];
-  uint32_t RelocType = MachO->getAnyRelocationType(RE);
-  bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
-  unsigned Size = MachO->getAnyRelocationLength(RE);
-  uint64_t Offset;
-  RelI->getOffset(Offset);
-  uint8_t *LocalAddress = Section.Address + Offset;
-  unsigned NumBytes = 1 << Size;
-  int64_t Addend = 0;
-  memcpy(&Addend, LocalAddress, NumBytes);
-
-  unsigned SymbolBaseAddr = MachO->getScatteredRelocationValue(RE);
-  section_iterator TargetSI = getSectionByAddress(*MachO, SymbolBaseAddr);
-  assert(TargetSI != MachO->section_end() && "Can't find section for symbol");
-  uint64_t SectionBaseAddr;
-  TargetSI->getAddress(SectionBaseAddr);
-  SectionRef TargetSection = *TargetSI;
-  bool IsCode;
-  TargetSection.isText(IsCode);
-  uint32_t TargetSectionID = findOrEmitSection(Obj, TargetSection, IsCode,
-                                               ObjSectionToID);
-
-  Addend -= SectionBaseAddr;
-  RelocationEntry R(SectionID, Offset, RelocType, Addend,
-                    IsPCRel, Size);
-
-  addRelocationForSection(R, TargetSectionID);
-
-  return ++RelI;
-}
-
-relocation_iterator RuntimeDyldMachO::processRelocationRef(
-    unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj,
-    ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols,
-    StubMap &Stubs) {
-  const ObjectFile *OF = Obj.getObjectFile();
-  const MachOObjectFile *MachO = static_cast<const MachOObjectFile *>(OF);
-  MachO::any_relocation_info RE =
-      MachO->getRelocation(RelI->getRawDataRefImpl());
-  int64_t RelocAddendValue = 0;
-  bool HasRelocAddendValue = false;
-
-  uint32_t RelType = MachO->getAnyRelocationType(RE);
-  if (Arch == Triple::arm64) {
-    // ARM64_RELOC_ADDEND provides the offset (addend) that will be used by the
-    // next relocation entry. Save the value and advance to the next relocation
-    // entry.
-    if (RelType == MachO::ARM64_RELOC_ADDEND) {
-      assert(!MachO->getPlainRelocationExternal(RE));
-      assert(!MachO->getAnyRelocationPCRel(RE));
-      assert(MachO->getAnyRelocationLength(RE) == 2);
-      uint64_t RawAddend = MachO->getPlainRelocationSymbolNum(RE);
-      // Sign-extend the 24-bit to 64-bit.
-      RelocAddendValue = RawAddend << 40;
-      RelocAddendValue >>= 40;
-      HasRelocAddendValue = true;
-
-      // Get the next entry.
-      RE = MachO->getRelocation((++RelI)->getRawDataRefImpl());
-      RelType = MachO->getAnyRelocationType(RE);
-      assert(RelType == MachO::ARM64_RELOC_BRANCH26 ||
-             RelType == MachO::ARM64_RELOC_PAGE21 ||
-             RelType == MachO::ARM64_RELOC_PAGEOFF12);
-
-    } else if (RelType == MachO::ARM64_RELOC_BRANCH26 ||
-               RelType == MachO::ARM64_RELOC_PAGE21 ||
-               RelType == MachO::ARM64_RELOC_PAGEOFF12 ||
-               RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
-               RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12) {
-      RelocAddendValue = 0;
-      HasRelocAddendValue = true;
-    }
-  }
-
-  // FIXME: Properly handle scattered relocations.
-  //        Special case the couple of scattered relocations that we know how
-  //        to handle: SECTDIFF relocations, and scattered VANILLA relocations
-  //        on I386.
-  //        For all other scattered relocations, just bail out and hope for the
-  //        best, since the offsets computed by scattered relocations have often
-  //        been optimisticaly filled in by the compiler. This will fail
-  //        horribly where the relocations *do* need to be applied, but that was
-  //        already the case.
-  if (MachO->isRelocationScattered(RE)) {
-    if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
-        RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
-      return processSECTDIFFRelocation(SectionID, RelI, Obj, ObjSectionToID);
-    else if (Arch == Triple::x86 && RelType == MachO::GENERIC_RELOC_VANILLA)
-      return processI386ScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
-    else
-      return ++RelI;
-  }
-
-  RelocationValueRef Value;
-  SectionEntry &Section = Sections[SectionID];
-
-  bool IsExtern = MachO->getPlainRelocationExternal(RE);
-  bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
-  unsigned Size = MachO->getAnyRelocationLength(RE);
-  uint64_t Offset;
-  RelI->getOffset(Offset);
-  uint8_t *LocalAddress = Section.Address + Offset;
-  unsigned NumBytes = 1 << Size;
-  int64_t Addend = 0;
-  if (HasRelocAddendValue)
-    Addend = RelocAddendValue;
-  else
-    memcpy(&Addend, LocalAddress, NumBytes);
-
-  if (IsExtern) {
-    // Obtain the symbol name which is referenced in the relocation
-    symbol_iterator Symbol = RelI->getSymbol();
-    StringRef TargetName;
-    Symbol->getName(TargetName);
-    // First search for the symbol in the local symbol table
-    SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
-    if (lsi != Symbols.end()) {
-      Value.SectionID = lsi->second.first;
-      Value.Addend = lsi->second.second + Addend;
-    } else {
-      // Search for the symbol in the global symbol table
-      SymbolTableMap::const_iterator gsi =
-          GlobalSymbolTable.find(TargetName.data());
-      if (gsi != GlobalSymbolTable.end()) {
-        Value.SectionID = gsi->second.first;
-        Value.Addend = gsi->second.second + Addend;
-      } else {
-        Value.SymbolName = TargetName.data();
-        Value.Addend = Addend;
-      }
-    }
-
-    // Addends for external, PC-rel relocations on i386 point back to the zero
-    // offset. Calculate the final offset from the relocation target instead.
-    // This allows us to use the same logic for both external and internal
-    // relocations in resolveI386RelocationRef.
-    if (Arch == Triple::x86 && IsPCRel) {
-      uint64_t RelocAddr = 0;
-      RelI->getAddress(RelocAddr);
-      Value.Addend += RelocAddr + 4;
-    }
-
-  } else {
-    SectionRef Sec = MachO->getRelocationSection(RE);
-    bool IsCode = false;
-    Sec.isText(IsCode);
-    Value.SectionID = findOrEmitSection(Obj, Sec, IsCode, ObjSectionToID);
-    uint64_t Addr;
-    Sec.getAddress(Addr);
-    Value.Addend = Addend - Addr;
-    if (IsPCRel)
-      Value.Addend += Offset + NumBytes;
-  }
-
-  if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT ||
-                                 RelType == MachO::X86_64_RELOC_GOT_LOAD)) {
-    assert(IsPCRel);
-    assert(Size == 2);
-
-    // FIXME: Teach the generic code above not to prematurely conflate
-    //        relocation addends and symbol offsets.
-    Value.Addend -= Addend;
-    StubMap::const_iterator i = Stubs.find(Value);
-    uint8_t *Addr;
-    if (i != Stubs.end()) {
-      Addr = Section.Address + i->second;
-    } else {
-      Stubs[Value] = Section.StubOffset;
-      uint8_t *GOTEntry = Section.Address + Section.StubOffset;
-      RelocationEntry GOTRE(SectionID, Section.StubOffset,
-                            MachO::X86_64_RELOC_UNSIGNED, Value.Addend, false,
-                            3);
-      if (Value.SymbolName)
-        addRelocationForSymbol(GOTRE, Value.SymbolName);
-      else
-        addRelocationForSection(GOTRE, Value.SectionID);
-      Section.StubOffset += 8;
-      Addr = GOTEntry;
-    }
-    RelocationEntry TargetRE(SectionID, Offset,
-                             MachO::X86_64_RELOC_UNSIGNED, Addend, true,
-                             2);
-    resolveRelocation(TargetRE, (uint64_t)Addr);
-  } else if (Arch == Triple::arm && (RelType & 0xf) == MachO::ARM_RELOC_BR24) {
-    // This is an ARM branch relocation, need to use a stub function.
-
-    //  Look up for existing stub.
-    StubMap::const_iterator i = Stubs.find(Value);
-    uint8_t *Addr;
-    if (i != Stubs.end()) {
-      Addr = Section.Address + i->second;
-    } else {
-      // Create a new stub function.
-      Stubs[Value] = Section.StubOffset;
-      uint8_t *StubTargetAddr =
-          createStubFunction(Section.Address + Section.StubOffset);
-      RelocationEntry StubRE(SectionID, StubTargetAddr - Section.Address,
-                             MachO::GENERIC_RELOC_VANILLA, Value.Addend);
-      if (Value.SymbolName)
-        addRelocationForSymbol(StubRE, Value.SymbolName);
-      else
-        addRelocationForSection(StubRE, Value.SectionID);
-      Addr = Section.Address + Section.StubOffset;
-      Section.StubOffset += getMaxStubSize();
-    }
-    RelocationEntry TargetRE(Value.SectionID, Offset, RelType, 0, IsPCRel,
-                             Size);
-    resolveRelocation(TargetRE, (uint64_t)Addr);
-  } else if (Arch == Triple::arm64 &&
-             (RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
-              RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12)) {
-    assert(Size == 2);
-    StubMap::const_iterator i = Stubs.find(Value);
-    uint8_t *Addr;
-    if (i != Stubs.end())
-      Addr = Section.Address + i->second;
-    else {
-      // FIXME: There must be a better way to do this then to check and fix the
-      // alignment every time!!!
-      uintptr_t BaseAddress = uintptr_t(Section.Address);
-      uintptr_t StubAlignment = getStubAlignment();
-      uintptr_t StubAddress
-        = (BaseAddress + Section.StubOffset + StubAlignment - 1) &
-          -StubAlignment;
-      unsigned StubOffset = StubAddress - BaseAddress;
-      Stubs[Value] = StubOffset;
-      assert(((StubAddress % getStubAlignment()) == 0) &&
-             "GOT entry not aligned");
-      RelocationEntry GOTRE(SectionID, StubOffset, MachO::ARM64_RELOC_UNSIGNED,
-                            Value.Addend, /*IsPCRel=*/false, /*Size=*/3);
-      if (Value.SymbolName)
-        addRelocationForSymbol(GOTRE, Value.SymbolName);
-      else
-        addRelocationForSection(GOTRE, Value.SectionID);
-      Section.StubOffset = StubOffset + getMaxStubSize();
-
-      Addr = (uint8_t *)StubAddress;
-    }
-    RelocationEntry TargetRE(SectionID, Offset, RelType, /*Addend=*/0, IsPCRel,
-                             Size);
-    resolveRelocation(TargetRE, (uint64_t)Addr);
-  } else {
-
-    RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size);
-    if (Value.SymbolName)
-      addRelocationForSymbol(RE, Value.SymbolName);
-    else
-      addRelocationForSection(RE, Value.SectionID);
-  }
-  return ++RelI;
-}
-
-bool
-RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const {
-  if (InputBuffer->getBufferSize() < 4)
-    return false;
-  StringRef Magic(InputBuffer->getBufferStart(), 4);
-  if (Magic == "\xFE\xED\xFA\xCE")
-    return true;
-  if (Magic == "\xCE\xFA\xED\xFE")
-    return true;
-  if (Magic == "\xFE\xED\xFA\xCF")
-    return true;
-  if (Magic == "\xCF\xFA\xED\xFE")
-    return true;
-  return false;
-}
-
-bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const {
-  return Obj->isMachO();
 }
 
 } // end namespace llvm
index 7025e22..c864282 100644 (file)
 #include "llvm/Object/MachO.h"
 #include "llvm/Support/Format.h"
 
+#define DEBUG_TYPE "dyld"
+
 using namespace llvm;
 using namespace llvm::object;
 
 namespace llvm {
 class RuntimeDyldMachO : public RuntimeDyldImpl {
-private:
-
-  /// Write the least significant 'Size' bytes in 'Value' out at the address
-  /// pointed to by Addr.
-  bool applyRelocationValue(uint8_t *Addr, uint64_t Value, unsigned Size) {
-    for (unsigned i = 0; i < Size; ++i) {
-      *Addr++ = (uint8_t)Value;
-      Value >>= 8;
-    }
-
-    return false;
-  }
-
-  bool resolveI386Relocation(const RelocationEntry &RE, uint64_t Value);
-  bool resolveX86_64Relocation(const RelocationEntry &RE, uint64_t Value);
-  bool resolveARMRelocation(const RelocationEntry &RE, uint64_t Value);
-  bool resolveAArch64Relocation(const RelocationEntry &RE, uint64_t Value);
-
-  // Populate stubs in __jump_table section.
-  void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection,
-                         unsigned JTSectionID);
-
-  // Populate __pointers section.
-  void populatePointersSection(MachOObjectFile &Obj, const SectionRef &PTSection,
-                               unsigned PTSectionID);
-
-  unsigned getMaxStubSize() override {
-    if (Arch == Triple::arm || Arch == Triple::thumb)
-      return 8; // 32-bit instruction and 32-bit address
-    else if (Arch == Triple::x86_64)
-      return 8; // GOT entry
-    else if (Arch == Triple::arm64)
-      return 8; // GOT entry
-    else
-      return 0;
-  }
-
-  unsigned getStubAlignment() override {
-    if (Arch == Triple::arm || Arch == Triple::thumb)
-      return 4;
-    else if (Arch == Triple::arm64)
-      return 8;
-    else
-      return 1;
-  }
-
-  relocation_iterator processSECTDIFFRelocation(
-                                             unsigned SectionID,
-                                             relocation_iterator RelI,
-                                             ObjectImage &ObjImg,
-                                             ObjSectionToIDMap &ObjSectionToID);
-
-  relocation_iterator processI386ScatteredVANILLA(
-                                            unsigned SectionID,
-                                            relocation_iterator RelI,
-                                            ObjectImage &ObjImg,
-                                            ObjSectionToIDMap &ObjSectionToID);
+protected:
+  struct SectionOffsetPair {
+    unsigned SectionID;
+    uint64_t Offset;
+  };
 
   struct EHFrameRelatedSections {
     EHFrameRelatedSections()
@@ -99,30 +49,105 @@ private:
   // EH frame sections with the memory manager.
   SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections;
 
-public:
   RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
 
-  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override;
-  relocation_iterator
-  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
-                       ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID,
-                       const SymbolTableMap &Symbols, StubMap &Stubs) override;
-  bool isCompatibleFormat(const ObjectBuffer *Buffer) const override;
-  bool isCompatibleFile(const object::ObjectFile *Obj) const override;
-  void registerEHFrames() override;
-  void finalizeLoad(ObjectImage &ObjImg,
-                    ObjSectionToIDMap &SectionMap) override;
+  /// Parse the given relocation, which must be a non-scattered, and
+  /// return a RelocationEntry representing the information. The 'Addend' field
+  /// will contain the unmodified instruction immediate.
+  RelocationEntry getBasicRelocationEntry(unsigned SectionID, ObjectImage &Obj,
+                                          const relocation_iterator &RI) const;
+
+  /// Construct a RelocationValueRef representing the relocation target.
+  /// For Symbols in known sections, this will return a RelocationValueRef
+  /// representing a (SectionID, Offset) pair.
+  /// For Symbols whose section is not known, this will return a
+  /// (SymbolName, Offset) pair, where the Offset is taken from the instruction
+  /// immediate (held in RE.Addend).
+  /// In both cases the Addend field is *NOT* fixed up to be PC-relative. That
+  /// should be done by the caller where appropriate by calling makePCRel on
+  /// the RelocationValueRef.
+  RelocationValueRef getRelocationValueRef(ObjectImage &ObjImg,
+                                           const relocation_iterator &RI,
+                                           const RelocationEntry &RE,
+                                           ObjSectionToIDMap &ObjSectionToID,
+                                           const SymbolTableMap &Symbols);
+
+  /// Make the RelocationValueRef addend PC-relative.
+  void makeValueAddendPCRel(RelocationValueRef &Value, ObjectImage &ObjImg,
+                            const relocation_iterator &RI);
+
+  /// Dump information about the relocation entry (RE) and resolved value.
+  void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const;
 
+public:
+  /// Create an ObjectImage from the given ObjectBuffer.
   static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer) {
     return new ObjectImageCommon(InputBuffer);
   }
 
+  /// Create an ObjectImage from the given ObjectFile.
   static ObjectImage *
   createObjectImageFromFile(std::unique_ptr<object::ObjectFile> InputObject) {
     return new ObjectImageCommon(std::move(InputObject));
   }
+
+  /// Create a RuntimeDyldMachO instance for the given target architecture.
+  static std::unique_ptr<RuntimeDyldMachO> create(Triple::ArchType Arch,
+                                                  RTDyldMemoryManager *mm);
+
+  /// Write the least significant 'Size' bytes in 'Value' out at the address
+  /// pointed to by Addr. Check for overflow.
+  bool writeBytesUnaligned(uint8_t *Addr, uint64_t Value, unsigned Size);
+
+  SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; }
+
+  bool isCompatibleFormat(const ObjectBuffer *Buffer) const override;
+  bool isCompatibleFile(const object::ObjectFile *Obj) const override;
+  void registerEHFrames() override;
+};
+
+/// RuntimeDyldMachOTarget - Templated base class for generic MachO linker
+/// algorithms and data structures.
+///
+/// Concrete, target specific sub-classes can be accessed via the impl()
+/// methods. (i.e. the RuntimeDyldMachO hierarchy uses the Curiously
+/// Recurring Template Idiom). Concrete subclasses for each target
+/// can be found in ./Targets.
+template <typename Impl>
+class RuntimeDyldMachOCRTPBase : public RuntimeDyldMachO {
+private:
+  Impl &impl() { return static_cast<Impl &>(*this); }
+  const Impl &impl() const { return static_cast<Impl &>(*this); }
+
+public:
+  RuntimeDyldMachOCRTPBase(RTDyldMemoryManager *mm) : RuntimeDyldMachO(mm) {}
+
+  void finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) {
+    unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID;
+    unsigned TextSID = RTDYLD_INVALID_SECTION_ID;
+    unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID;
+    ObjSectionToIDMap::iterator i, e;
+
+    for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) {
+      const SectionRef &Section = i->first;
+      StringRef Name;
+      Section.getName(Name);
+      if (Name == "__eh_frame")
+        EHFrameSID = i->second;
+      else if (Name == "__text")
+        TextSID = i->second;
+      else if (Name == "__gcc_except_tab")
+        ExceptTabSID = i->second;
+      else
+        impl().finalizeSection(ObjImg, i->second, Section);
+    }
+    UnregisteredEHFrameSections.push_back(
+        EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID));
+  }
 };
 
 } // end namespace llvm
 
+#undef DEBUG_TYPE
+
 #endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
new file mode 100644 (file)
index 0000000..c9fcede
--- /dev/null
@@ -0,0 +1,253 @@
+//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_RUNTIMEDYLDMACHOAARCH64_H
+#define LLVM_RUNTIMEDYLDMACHOAARCH64_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOAArch64
+    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
+public:
+  RuntimeDyldMachOAArch64(RTDyldMemoryManager *MM)
+      : RuntimeDyldMachOCRTPBase(MM) {}
+
+  unsigned getMaxStubSize() override { return 8; }
+
+  unsigned getStubAlignment() override { return 1; }
+
+  relocation_iterator
+  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+                       ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+                       const SymbolTableMap &Symbols, StubMap &Stubs) override {
+    const MachOObjectFile &Obj =
+        static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+    MachO::any_relocation_info RelInfo =
+        Obj.getRelocation(RelI->getRawDataRefImpl());
+
+    assert(!Obj.isRelocationScattered(RelInfo) && "");
+
+    // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit
+    // addend for the following relocation. If found: (1) store the associated
+    // addend, (2) consume the next relocation, and (3) use the stored addend to
+    // override the addend.
+    bool HasExplicitAddend = false;
+    int64_t ExplicitAddend = 0;
+    if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) {
+      assert(!Obj.getPlainRelocationExternal(RelInfo));
+      assert(!Obj.getAnyRelocationPCRel(RelInfo));
+      assert(Obj.getAnyRelocationLength(RelInfo) == 2);
+      HasExplicitAddend = true;
+      int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
+      // Sign-extend the 24-bit to 64-bit.
+      ExplicitAddend = (RawAddend << 40) >> 40;
+      ++RelI;
+      RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
+    }
+
+    RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI));
+    RelocationValueRef Value(
+        getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+    if (HasExplicitAddend)
+      Value.Addend = ExplicitAddend;
+
+    bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+    if (!IsExtern && RE.IsPCRel)
+      makeValueAddendPCRel(Value, ObjImg, RelI);
+
+    RE.Addend = Value.Addend;
+
+    if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
+        RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12)
+      processGOTRelocation(RE, Value, Stubs);
+    else {
+      if (Value.SymbolName)
+        addRelocationForSymbol(RE, Value.SymbolName);
+      else
+        addRelocationForSection(RE, Value.SectionID);
+    }
+
+    return ++RelI;
+  }
+
+  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) {
+    DEBUG(dumpRelocationToResolve(RE, Value));
+
+    const SectionEntry &Section = Sections[RE.SectionID];
+    uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+    switch (RE.RelType) {
+    default:
+      llvm_unreachable("Invalid relocation type!");
+    case MachO::ARM64_RELOC_UNSIGNED: {
+      assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
+      // Mask in the target value a byte at a time (we don't have an alignment
+      // guarantee for the target address, so this is safest).
+      if (RE.Size < 2)
+        llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
+
+      writeBytesUnaligned(LocalAddress, Value + RE.Addend, 1 << RE.Size);
+      break;
+    }
+    case MachO::ARM64_RELOC_BRANCH26: {
+      assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
+      // Mask the value into the target address. We know instructions are
+      // 32-bit aligned, so we can do it all at once.
+      uint32_t *p = (uint32_t *)LocalAddress;
+      // Check if the addend is encoded in the instruction.
+      uint32_t EncodedAddend = *p & 0x03FFFFFF;
+      if (EncodedAddend != 0) {
+        if (RE.Addend == 0)
+          llvm_unreachable("branch26 instruction has embedded addend.");
+        else
+          llvm_unreachable("branch26 instruction has embedded addend and"
+                           "ARM64_RELOC_ADDEND.");
+      }
+      // Check if branch is in range.
+      uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+      uint64_t PCRelVal = Value - FinalAddress + RE.Addend;
+      assert(isInt<26>(PCRelVal) && "Branch target out of range!");
+      // Insert the value into the instruction.
+      *p = (*p & 0xFC000000) | ((uint32_t)(PCRelVal >> 2) & 0x03FFFFFF);
+      break;
+    }
+    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+    case MachO::ARM64_RELOC_PAGE21: {
+      assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
+      // Mask the value into the target address. We know instructions are
+      // 32-bit aligned, so we can do it all at once.
+      uint32_t *p = (uint32_t *)LocalAddress;
+      // Check if the addend is encoded in the instruction.
+      uint32_t EncodedAddend =
+          ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3);
+      if (EncodedAddend != 0) {
+        if (RE.Addend == 0)
+          llvm_unreachable("adrp instruction has embedded addend.");
+        else
+          llvm_unreachable("adrp instruction has embedded addend and"
+                           "ARM64_RELOC_ADDEND.");
+      }
+      // Adjust for PC-relative relocation and offset.
+      uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+      uint64_t PCRelVal =
+          ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
+      // Check that the value fits into 21 bits (+ 12 lower bits).
+      assert(isInt<33>(PCRelVal) && "Invalid page reloc value!");
+      // Insert the value into the instruction.
+      uint32_t ImmLoValue = (uint32_t)(PCRelVal << 17) & 0x60000000;
+      uint32_t ImmHiValue = (uint32_t)(PCRelVal >> 9) & 0x00FFFFE0;
+      *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
+      break;
+    }
+    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+    case MachO::ARM64_RELOC_PAGEOFF12: {
+      assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
+      // Mask the value into the target address. We know instructions are
+      // 32-bit aligned, so we can do it all at once.
+      uint32_t *p = (uint32_t *)LocalAddress;
+      // Check if the addend is encoded in the instruction.
+      uint32_t EncodedAddend = *p & 0x003FFC00;
+      if (EncodedAddend != 0) {
+        if (RE.Addend == 0)
+          llvm_unreachable("adrp instruction has embedded addend.");
+        else
+          llvm_unreachable("adrp instruction has embedded addend and"
+                           "ARM64_RELOC_ADDEND.");
+      }
+      // Add the offset from the symbol.
+      Value += RE.Addend;
+      // Mask out the page address and only use the lower 12 bits.
+      Value &= 0xFFF;
+      // Check which instruction we are updating to obtain the implicit shift
+      // factor from LDR/STR instructions.
+      if (*p & 0x08000000) {
+        uint32_t ImplicitShift = ((*p >> 30) & 0x3);
+        switch (ImplicitShift) {
+        case 0:
+          // Check if this a vector op.
+          if ((*p & 0x04800000) == 0x04800000) {
+            ImplicitShift = 4;
+            assert(((Value & 0xF) == 0) &&
+                   "128-bit LDR/STR not 16-byte aligned.");
+          }
+          break;
+        case 1:
+          assert(((Value & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
+        case 2:
+          assert(((Value & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
+        case 3:
+          assert(((Value & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
+        }
+        // Compensate for implicit shift.
+        Value >>= ImplicitShift;
+      }
+      // Insert the value into the instruction.
+      *p = (*p & 0xFFC003FF) | ((uint32_t)(Value << 10) & 0x003FFC00);
+      break;
+    }
+    case MachO::ARM64_RELOC_SUBTRACTOR:
+    case MachO::ARM64_RELOC_POINTER_TO_GOT:
+    case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
+    case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
+      llvm_unreachable("Relocation type not implemented yet!");
+    case MachO::ARM64_RELOC_ADDEND:
+      llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
+                       "processRelocationRef!");
+    }
+  }
+
+  void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+                       const SectionRef &Section) {}
+
+private:
+  void processGOTRelocation(const RelocationEntry &RE,
+                            RelocationValueRef &Value, StubMap &Stubs) {
+    assert(RE.Size == 2);
+    SectionEntry &Section = Sections[RE.SectionID];
+    StubMap::const_iterator i = Stubs.find(Value);
+    uint8_t *Addr;
+    if (i != Stubs.end())
+      Addr = Section.Address + i->second;
+    else {
+      // FIXME: There must be a better way to do this then to check and fix the
+      // alignment every time!!!
+      uintptr_t BaseAddress = uintptr_t(Section.Address);
+      uintptr_t StubAlignment = getStubAlignment();
+      uintptr_t StubAddress =
+          (BaseAddress + Section.StubOffset + StubAlignment - 1) &
+          -StubAlignment;
+      unsigned StubOffset = StubAddress - BaseAddress;
+      Stubs[Value] = StubOffset;
+      assert(((StubAddress % getStubAlignment()) == 0) &&
+             "GOT entry not aligned");
+      RelocationEntry GOTRE(RE.SectionID, StubOffset,
+                            MachO::ARM64_RELOC_UNSIGNED, Value.Addend,
+                            /*IsPCRel=*/false, /*Size=*/3);
+      if (Value.SymbolName)
+        addRelocationForSymbol(GOTRE, Value.SymbolName);
+      else
+        addRelocationForSection(GOTRE, Value.SectionID);
+      Section.StubOffset = StubOffset + getMaxStubSize();
+      Addr = (uint8_t *)StubAddress;
+    }
+    RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, /*Addend=*/0,
+                             RE.IsPCRel, RE.Size);
+    resolveRelocation(TargetRE, (uint64_t)Addr);
+  }
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_RUNTIMEDYLDMACHOAARCH64_H
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
new file mode 100644 (file)
index 0000000..7e14992
--- /dev/null
@@ -0,0 +1,154 @@
+//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_RUNTIMEDYLDMACHOARM_H
+#define LLVM_RUNTIMEDYLDMACHOARM_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOARM
+    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
+public:
+  RuntimeDyldMachOARM(RTDyldMemoryManager *MM) : RuntimeDyldMachOCRTPBase(MM) {}
+
+  unsigned getMaxStubSize() override { return 8; }
+
+  unsigned getStubAlignment() override { return 1; }
+
+  relocation_iterator
+  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+                       ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+                       const SymbolTableMap &Symbols, StubMap &Stubs) override {
+    const MachOObjectFile &Obj =
+        static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+    MachO::any_relocation_info RelInfo =
+        Obj.getRelocation(RelI->getRawDataRefImpl());
+
+    if (Obj.isRelocationScattered(RelInfo))
+      return ++++RelI;
+
+    RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI));
+    RelocationValueRef Value(
+        getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+    bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+    if (!IsExtern && RE.IsPCRel)
+      makeValueAddendPCRel(Value, ObjImg, RelI);
+
+    if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
+      processBranchRelocation(RE, Value, Stubs);
+    else {
+      RE.Addend = Value.Addend;
+      if (Value.SymbolName)
+        addRelocationForSymbol(RE, Value.SymbolName);
+      else
+        addRelocationForSection(RE, Value.SectionID);
+    }
+
+    return ++RelI;
+  }
+
+  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) {
+    DEBUG(dumpRelocationToResolve(RE, Value));
+    const SectionEntry &Section = Sections[RE.SectionID];
+    uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+    // If the relocation is PC-relative, the value to be encoded is the
+    // pointer difference.
+    if (RE.IsPCRel) {
+      uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+      Value -= FinalAddress;
+      // ARM PCRel relocations have an effective-PC offset of two instructions
+      // (four bytes in Thumb mode, 8 bytes in ARM mode).
+      // FIXME: For now, assume ARM mode.
+      Value -= 8;
+    }
+
+    switch (RE.RelType) {
+    default:
+      llvm_unreachable("Invalid relocation type!");
+    case MachO::ARM_RELOC_VANILLA:
+      writeBytesUnaligned(LocalAddress, Value, 1 << RE.Size);
+      break;
+    case MachO::ARM_RELOC_BR24: {
+      // Mask the value into the target address. We know instructions are
+      // 32-bit aligned, so we can do it all at once.
+      uint32_t *p = (uint32_t *)LocalAddress;
+      // The low two bits of the value are not encoded.
+      Value >>= 2;
+      // Mask the value to 24 bits.
+      uint64_t FinalValue = Value & 0xffffff;
+      // Check for overflow.
+      if (Value != FinalValue) {
+        Error("ARM BR24 relocation out of range.");
+        return;
+      }
+      // FIXME: If the destination is a Thumb function (and the instruction
+      // is a non-predicated BL instruction), we need to change it to a BLX
+      // instruction instead.
+
+      // Insert the value into the instruction.
+      *p = (*p & ~0xffffff) | FinalValue;
+      break;
+    }
+    case MachO::ARM_THUMB_RELOC_BR22:
+    case MachO::ARM_THUMB_32BIT_BRANCH:
+    case MachO::ARM_RELOC_HALF:
+    case MachO::ARM_RELOC_HALF_SECTDIFF:
+    case MachO::ARM_RELOC_PAIR:
+    case MachO::ARM_RELOC_SECTDIFF:
+    case MachO::ARM_RELOC_LOCAL_SECTDIFF:
+    case MachO::ARM_RELOC_PB_LA_PTR:
+      Error("Relocation type not implemented yet!");
+      return;
+    }
+  }
+
+  void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+                       const SectionRef &Section) {}
+
+private:
+  void processBranchRelocation(const RelocationEntry &RE,
+                               const RelocationValueRef &Value,
+                               StubMap &Stubs) {
+    // This is an ARM branch relocation, need to use a stub function.
+    // Look up for existing stub.
+    SectionEntry &Section = Sections[RE.SectionID];
+    RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
+    uint8_t *Addr;
+    if (i != Stubs.end()) {
+      Addr = Section.Address + i->second;
+    } else {
+      // Create a new stub function.
+      Stubs[Value] = Section.StubOffset;
+      uint8_t *StubTargetAddr =
+          createStubFunction(Section.Address + Section.StubOffset);
+      RelocationEntry StubRE(RE.SectionID, StubTargetAddr - Section.Address,
+                             MachO::GENERIC_RELOC_VANILLA, Value.Addend);
+      if (Value.SymbolName)
+        addRelocationForSymbol(StubRE, Value.SymbolName);
+      else
+        addRelocationForSection(StubRE, Value.SectionID);
+      Addr = Section.Address + Section.StubOffset;
+      Section.StubOffset += getMaxStubSize();
+    }
+    RelocationEntry TargetRE(Value.SectionID, RE.Offset, RE.RelType, 0,
+                             RE.IsPCRel, RE.Size);
+    resolveRelocation(TargetRE, (uint64_t)Addr);
+  }
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_RUNTIMEDYLDMACHOARM_H
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h
new file mode 100644 (file)
index 0000000..856c6ca
--- /dev/null
@@ -0,0 +1,315 @@
+//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_RUNTIMEDYLDMACHOI386_H
+#define LLVM_RUNTIMEDYLDMACHOI386_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOI386
+    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> {
+public:
+  RuntimeDyldMachOI386(RTDyldMemoryManager *MM)
+      : RuntimeDyldMachOCRTPBase(MM) {}
+
+  unsigned getMaxStubSize() override { return 0; }
+
+  unsigned getStubAlignment() override { return 1; }
+
+  relocation_iterator
+  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+                       ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+                       const SymbolTableMap &Symbols, StubMap &Stubs) override {
+    const MachOObjectFile &Obj =
+        static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+    MachO::any_relocation_info RelInfo =
+        Obj.getRelocation(RelI->getRawDataRefImpl());
+    uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
+
+    if (Obj.isRelocationScattered(RelInfo)) {
+      if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
+          RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
+        return processSECTDIFFRelocation(SectionID, RelI, ObjImg,
+                                         ObjSectionToID);
+      else if (Arch == Triple::x86 && RelType == MachO::GENERIC_RELOC_VANILLA)
+        return processI386ScatteredVANILLA(SectionID, RelI, ObjImg,
+                                           ObjSectionToID);
+      llvm_unreachable("Unhandled scattered relocation.");
+    }
+
+    RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI));
+    RelocationValueRef Value(
+        getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+    // Addends for external, PC-rel relocations on i386 point back to the zero
+    // offset. Calculate the final offset from the relocation target instead.
+    // This allows us to use the same logic for both external and internal
+    // relocations in resolveI386RelocationRef.
+    // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+    // if (IsExtern && RE.IsPCRel) {
+    //   uint64_t RelocAddr = 0;
+    //   RelI->getAddress(RelocAddr);
+    //   Value.Addend += RelocAddr + 4;
+    // }
+    if (RE.IsPCRel)
+      makeValueAddendPCRel(Value, ObjImg, RelI);
+
+    RE.Addend = Value.Addend;
+
+    if (Value.SymbolName)
+      addRelocationForSymbol(RE, Value.SymbolName);
+    else
+      addRelocationForSection(RE, Value.SectionID);
+
+    return ++RelI;
+  }
+
+  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) {
+    DEBUG(dumpRelocationToResolve(RE, Value));
+
+    const SectionEntry &Section = Sections[RE.SectionID];
+    uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+    if (RE.IsPCRel) {
+      uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+      Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
+    }
+
+    switch (RE.RelType) {
+    default:
+      llvm_unreachable("Invalid relocation type!");
+    case MachO::GENERIC_RELOC_VANILLA:
+      writeBytesUnaligned(LocalAddress, Value + RE.Addend, 1 << RE.Size);
+      break;
+    case MachO::GENERIC_RELOC_SECTDIFF:
+    case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
+      uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
+      uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
+      assert((Value == SectionABase || Value == SectionBBase) &&
+             "Unexpected SECTDIFF relocation value.");
+      Value = SectionABase - SectionBBase + RE.Addend;
+      writeBytesUnaligned(LocalAddress, Value, 1 << RE.Size);
+      break;
+    }
+    case MachO::GENERIC_RELOC_PB_LA_PTR:
+      Error("Relocation type not implemented yet!");
+    }
+  }
+
+  void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+                       const SectionRef &Section) {
+    StringRef Name;
+    Section.getName(Name);
+
+    if (Name == "__jump_table")
+      populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()), Section,
+                        SectionID);
+    else if (Name == "__pointers")
+      populatePointersSection(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
+                              Section, SectionID);
+  }
+
+private:
+  relocation_iterator
+  processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
+                            ObjectImage &Obj,
+                            ObjSectionToIDMap &ObjSectionToID) {
+    const MachOObjectFile *MachO =
+        static_cast<const MachOObjectFile *>(Obj.getObjectFile());
+    MachO::any_relocation_info RE =
+        MachO->getRelocation(RelI->getRawDataRefImpl());
+
+    SectionEntry &Section = Sections[SectionID];
+    uint32_t RelocType = MachO->getAnyRelocationType(RE);
+    bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
+    unsigned Size = MachO->getAnyRelocationLength(RE);
+    uint64_t Offset;
+    RelI->getOffset(Offset);
+    uint8_t *LocalAddress = Section.Address + Offset;
+    unsigned NumBytes = 1 << Size;
+    int64_t Addend = 0;
+    memcpy(&Addend, LocalAddress, NumBytes);
+
+    ++RelI;
+    MachO::any_relocation_info RE2 =
+        MachO->getRelocation(RelI->getRawDataRefImpl());
+
+    uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
+    section_iterator SAI = getSectionByAddress(*MachO, AddrA);
+    assert(SAI != MachO->section_end() && "Can't find section for address A");
+    uint64_t SectionABase;
+    SAI->getAddress(SectionABase);
+    uint64_t SectionAOffset = AddrA - SectionABase;
+    SectionRef SectionA = *SAI;
+    bool IsCode;
+    SectionA.isText(IsCode);
+    uint32_t SectionAID =
+        findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID);
+
+    uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
+    section_iterator SBI = getSectionByAddress(*MachO, AddrB);
+    assert(SBI != MachO->section_end() && "Can't find section for address B");
+    uint64_t SectionBBase;
+    SBI->getAddress(SectionBBase);
+    uint64_t SectionBOffset = AddrB - SectionBBase;
+    SectionRef SectionB = *SBI;
+    uint32_t SectionBID =
+        findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID);
+
+    if (Addend != AddrA - AddrB)
+      Error("Unexpected SECTDIFF relocation addend.");
+
+    DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
+                 << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
+                 << ", SectionAOffset: " << SectionAOffset
+                 << ", SectionB ID: " << SectionBID
+                 << ", SectionBOffset: " << SectionBOffset << "\n");
+    RelocationEntry R(SectionID, Offset, RelocType, 0, SectionAID,
+                      SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
+                      Size);
+
+    addRelocationForSection(R, SectionAID);
+    addRelocationForSection(R, SectionBID);
+
+    return ++RelI;
+  }
+
+  relocation_iterator processI386ScatteredVANILLA(
+      unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj,
+      RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID) {
+    const MachOObjectFile *MachO =
+        static_cast<const MachOObjectFile *>(Obj.getObjectFile());
+    MachO::any_relocation_info RE =
+        MachO->getRelocation(RelI->getRawDataRefImpl());
+
+    SectionEntry &Section = Sections[SectionID];
+    uint32_t RelocType = MachO->getAnyRelocationType(RE);
+    bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
+    unsigned Size = MachO->getAnyRelocationLength(RE);
+    uint64_t Offset;
+    RelI->getOffset(Offset);
+    uint8_t *LocalAddress = Section.Address + Offset;
+    unsigned NumBytes = 1 << Size;
+    int64_t Addend = 0;
+    memcpy(&Addend, LocalAddress, NumBytes);
+
+    unsigned SymbolBaseAddr = MachO->getScatteredRelocationValue(RE);
+    section_iterator TargetSI = getSectionByAddress(*MachO, SymbolBaseAddr);
+    assert(TargetSI != MachO->section_end() && "Can't find section for symbol");
+    uint64_t SectionBaseAddr;
+    TargetSI->getAddress(SectionBaseAddr);
+    SectionRef TargetSection = *TargetSI;
+    bool IsCode;
+    TargetSection.isText(IsCode);
+    uint32_t TargetSectionID =
+        findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID);
+
+    Addend -= SectionBaseAddr;
+    RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size);
+
+    addRelocationForSection(R, TargetSectionID);
+
+    return ++RelI;
+  }
+
+  // Populate stubs in __jump_table section.
+  void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection,
+                         unsigned JTSectionID) {
+    assert(!Obj.is64Bit() &&
+           "__jump_table section not supported in 64-bit MachO.");
+
+    MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
+    MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
+    uint32_t JTSectionSize = Sec32.size;
+    unsigned FirstIndirectSymbol = Sec32.reserved1;
+    unsigned JTEntrySize = Sec32.reserved2;
+    unsigned NumJTEntries = JTSectionSize / JTEntrySize;
+    uint8_t *JTSectionAddr = getSectionAddress(JTSectionID);
+    unsigned JTEntryOffset = 0;
+
+    assert((JTSectionSize % JTEntrySize) == 0 &&
+           "Jump-table section does not contain a whole number of stubs?");
+
+    for (unsigned i = 0; i < NumJTEntries; ++i) {
+      unsigned SymbolIndex =
+          Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
+      symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
+      StringRef IndirectSymbolName;
+      SI->getName(IndirectSymbolName);
+      uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset;
+      createStubFunction(JTEntryAddr);
+      RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
+                         MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
+      addRelocationForSymbol(RE, IndirectSymbolName);
+      JTEntryOffset += JTEntrySize;
+    }
+  }
+
+  // Populate __pointers section.
+  void populatePointersSection(MachOObjectFile &Obj,
+                               const SectionRef &PTSection,
+                               unsigned PTSectionID) {
+    assert(!Obj.is64Bit() &&
+           "__pointers section not supported in 64-bit MachO.");
+
+    MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
+    MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl());
+    uint32_t PTSectionSize = Sec32.size;
+    unsigned FirstIndirectSymbol = Sec32.reserved1;
+    const unsigned PTEntrySize = 4;
+    unsigned NumPTEntries = PTSectionSize / PTEntrySize;
+    unsigned PTEntryOffset = 0;
+
+    assert((PTSectionSize % PTEntrySize) == 0 &&
+           "Pointers section does not contain a whole number of stubs?");
+
+    DEBUG(dbgs() << "Populating __pointers, Section ID " << PTSectionID << ", "
+                 << NumPTEntries << " entries, " << PTEntrySize
+                 << " bytes each:\n");
+
+    for (unsigned i = 0; i < NumPTEntries; ++i) {
+      unsigned SymbolIndex =
+          Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
+      symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
+      StringRef IndirectSymbolName;
+      SI->getName(IndirectSymbolName);
+      DEBUG(dbgs() << "  " << IndirectSymbolName << ": index " << SymbolIndex
+                   << ", PT offset: " << PTEntryOffset << "\n");
+      RelocationEntry RE(PTSectionID, PTEntryOffset,
+                         MachO::GENERIC_RELOC_VANILLA, 0, false, 2);
+      addRelocationForSymbol(RE, IndirectSymbolName);
+      PTEntryOffset += PTEntrySize;
+    }
+  }
+
+  static section_iterator getSectionByAddress(const MachOObjectFile &Obj,
+                                              uint64_t Addr) {
+    section_iterator SI = Obj.section_begin();
+    section_iterator SE = Obj.section_end();
+
+    for (; SI != SE; ++SI) {
+      uint64_t SAddr, SSize;
+      SI->getAddress(SAddr);
+      SI->getSize(SSize);
+      if ((Addr >= SAddr) && (Addr < SAddr + SSize))
+        return SI;
+    }
+
+    return SE;
+  }
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_RUNTIMEDYLDMACHOI386_H
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h
new file mode 100644 (file)
index 0000000..99efe9d
--- /dev/null
@@ -0,0 +1,132 @@
+//===-- RuntimeDyldMachOX86_64.h ---- MachO/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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_RUNTIMEDYLDMACHOX86_64_H
+#define LLVM_RUNTIMEDYLDMACHOX86_64_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOX86_64
+    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> {
+public:
+  RuntimeDyldMachOX86_64(RTDyldMemoryManager *MM)
+      : RuntimeDyldMachOCRTPBase(MM) {}
+
+  unsigned getMaxStubSize() override { return 8; }
+
+  unsigned getStubAlignment() override { return 1; }
+
+  relocation_iterator
+  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+                       ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+                       const SymbolTableMap &Symbols, StubMap &Stubs) override {
+    const MachOObjectFile &Obj =
+        static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+    MachO::any_relocation_info RelInfo =
+        Obj.getRelocation(RelI->getRawDataRefImpl());
+
+    assert(!Obj.isRelocationScattered(RelInfo) &&
+           "Scattered relocations not supported on X86_64");
+
+    RelocationEntry RE(getBasicRelocationEntry(SectionID, ObjImg, RelI));
+    RelocationValueRef Value(
+        getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+    bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+    if (!IsExtern && RE.IsPCRel)
+      makeValueAddendPCRel(Value, ObjImg, RelI);
+
+    if (RE.RelType == MachO::X86_64_RELOC_GOT ||
+        RE.RelType == MachO::X86_64_RELOC_GOT_LOAD)
+      processGOTRelocation(RE, Value, Stubs);
+    else {
+      RE.Addend = Value.Addend;
+      if (Value.SymbolName)
+        addRelocationForSymbol(RE, Value.SymbolName);
+      else
+        addRelocationForSection(RE, Value.SectionID);
+    }
+
+    return ++RelI;
+  }
+
+  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) {
+    DEBUG(dumpRelocationToResolve(RE, Value));
+    const SectionEntry &Section = Sections[RE.SectionID];
+    uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+    // If the relocation is PC-relative, the value to be encoded is the
+    // pointer difference.
+    if (RE.IsPCRel) {
+      // FIXME: It seems this value needs to be adjusted by 4 for an effective
+      // PC address. Is that expected? Only for branches, perhaps?
+      uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+      Value -= FinalAddress + 4;
+    }
+
+    switch (RE.RelType) {
+    default:
+      llvm_unreachable("Invalid relocation type!");
+    case MachO::X86_64_RELOC_SIGNED_1:
+    case MachO::X86_64_RELOC_SIGNED_2:
+    case MachO::X86_64_RELOC_SIGNED_4:
+    case MachO::X86_64_RELOC_SIGNED:
+    case MachO::X86_64_RELOC_UNSIGNED:
+    case MachO::X86_64_RELOC_BRANCH:
+      writeBytesUnaligned(LocalAddress, Value + RE.Addend, 1 << RE.Size);
+      break;
+    case MachO::X86_64_RELOC_GOT_LOAD:
+    case MachO::X86_64_RELOC_GOT:
+    case MachO::X86_64_RELOC_SUBTRACTOR:
+    case MachO::X86_64_RELOC_TLV:
+      Error("Relocation type not implemented yet!");
+    }
+  }
+
+  void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+                       const SectionRef &Section) {}
+
+private:
+  void processGOTRelocation(const RelocationEntry &RE,
+                            RelocationValueRef &Value, StubMap &Stubs) {
+    SectionEntry &Section = Sections[RE.SectionID];
+    assert(RE.IsPCRel);
+    assert(RE.Size == 2);
+    Value.Addend -= RE.Addend;
+    RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
+    uint8_t *Addr;
+    if (i != Stubs.end()) {
+      Addr = Section.Address + i->second;
+    } else {
+      Stubs[Value] = Section.StubOffset;
+      uint8_t *GOTEntry = Section.Address + Section.StubOffset;
+      RelocationEntry GOTRE(RE.SectionID, Section.StubOffset,
+                            MachO::X86_64_RELOC_UNSIGNED, Value.Addend, false,
+                            3);
+      if (Value.SymbolName)
+        addRelocationForSymbol(GOTRE, Value.SymbolName);
+      else
+        addRelocationForSection(GOTRE, Value.SectionID);
+      Section.StubOffset += 8;
+      Addr = GOTEntry;
+    }
+    RelocationEntry TargetRE(RE.SectionID, RE.Offset,
+                             MachO::X86_64_RELOC_UNSIGNED, RE.Addend, true, 2);
+    resolveRelocation(TargetRE, (uint64_t)Addr);
+  }
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_RUNTIMEDYLDMACHOX86_64_H