542 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			542 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
 | 
						|
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
 | 
						|
 | 
						|
#include "../RuntimeDyldMachO.h"
 | 
						|
#include "llvm/Support/Endian.h"
 | 
						|
 | 
						|
#define DEBUG_TYPE "dyld"
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
 | 
						|
class RuntimeDyldMachOAArch64
 | 
						|
    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
 | 
						|
public:
 | 
						|
 | 
						|
  typedef uint64_t TargetPtrT;
 | 
						|
 | 
						|
  RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM,
 | 
						|
                          JITSymbolResolver &Resolver)
 | 
						|
      : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
 | 
						|
 | 
						|
  unsigned getMaxStubSize() const override { return 8; }
 | 
						|
 | 
						|
  unsigned getStubAlignment() override { return 8; }
 | 
						|
 | 
						|
  /// Extract the addend encoded in the instruction / memory location.
 | 
						|
  Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
 | 
						|
    const SectionEntry &Section = Sections[RE.SectionID];
 | 
						|
    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
 | 
						|
    unsigned NumBytes = 1 << RE.Size;
 | 
						|
    int64_t Addend = 0;
 | 
						|
    // Verify that the relocation has the correct size and alignment.
 | 
						|
    switch (RE.RelType) {
 | 
						|
    default: {
 | 
						|
      std::string ErrMsg;
 | 
						|
      {
 | 
						|
        raw_string_ostream ErrStream(ErrMsg);
 | 
						|
        ErrStream << "Unsupported relocation type: "
 | 
						|
                  << getRelocName(RE.RelType);
 | 
						|
      }
 | 
						|
      return make_error<StringError>(std::move(ErrMsg),
 | 
						|
                                     inconvertibleErrorCode());
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_POINTER_TO_GOT:
 | 
						|
    case MachO::ARM64_RELOC_UNSIGNED: {
 | 
						|
      if (NumBytes != 4 && NumBytes != 8) {
 | 
						|
        std::string ErrMsg;
 | 
						|
        {
 | 
						|
          raw_string_ostream ErrStream(ErrMsg);
 | 
						|
          ErrStream << "Invalid relocation size for relocation "
 | 
						|
                    << getRelocName(RE.RelType);
 | 
						|
        }
 | 
						|
        return make_error<StringError>(std::move(ErrMsg),
 | 
						|
                                       inconvertibleErrorCode());
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_BRANCH26:
 | 
						|
    case MachO::ARM64_RELOC_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_PAGEOFF12:
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
 | 
						|
      assert(NumBytes == 4 && "Invalid relocation size.");
 | 
						|
      assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
 | 
						|
             "Instruction address is not aligned to 4 bytes.");
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (RE.RelType) {
 | 
						|
    default:
 | 
						|
      llvm_unreachable("Unsupported relocation type!");
 | 
						|
    case MachO::ARM64_RELOC_POINTER_TO_GOT:
 | 
						|
    case MachO::ARM64_RELOC_UNSIGNED:
 | 
						|
      // This could be an unaligned memory location.
 | 
						|
      if (NumBytes == 4)
 | 
						|
        Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress);
 | 
						|
      else
 | 
						|
        Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
 | 
						|
      break;
 | 
						|
    case MachO::ARM64_RELOC_BRANCH26: {
 | 
						|
      // Verify that the relocation points to a B/BL instruction.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      assert(((*p & 0xFC000000) == 0x14000000 ||
 | 
						|
              (*p & 0xFC000000) == 0x94000000) &&
 | 
						|
             "Expected branch instruction.");
 | 
						|
 | 
						|
      // Get the 26 bit addend encoded in the branch instruction and sign-extend
 | 
						|
      // to 64 bit. The lower 2 bits are always zeros and are therefore implicit
 | 
						|
      // (<< 2).
 | 
						|
      Addend = (*p & 0x03FFFFFF) << 2;
 | 
						|
      Addend = SignExtend64(Addend, 28);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_PAGE21: {
 | 
						|
      // Verify that the relocation points to the expected adrp instruction.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
 | 
						|
 | 
						|
      // Get the 21 bit addend encoded in the adrp instruction and sign-extend
 | 
						|
      // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are
 | 
						|
      // therefore implicit (<< 12).
 | 
						|
      Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12;
 | 
						|
      Addend = SignExtend64(Addend, 33);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
 | 
						|
      // Verify that the relocation points to one of the expected load / store
 | 
						|
      // instructions.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      (void)p;
 | 
						|
      assert((*p & 0x3B000000) == 0x39000000 &&
 | 
						|
             "Only expected load / store instructions.");
 | 
						|
      LLVM_FALLTHROUGH;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_PAGEOFF12: {
 | 
						|
      // Verify that the relocation points to one of the expected load / store
 | 
						|
      // or add / sub instructions.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      assert((((*p & 0x3B000000) == 0x39000000) ||
 | 
						|
              ((*p & 0x11C00000) == 0x11000000)   ) &&
 | 
						|
             "Expected load / store  or add/sub instruction.");
 | 
						|
 | 
						|
      // Get the 12 bit addend encoded in the instruction.
 | 
						|
      Addend = (*p & 0x003FFC00) >> 10;
 | 
						|
 | 
						|
      // Check which instruction we are decoding to obtain the implicit shift
 | 
						|
      // factor of the instruction.
 | 
						|
      int ImplicitShift = 0;
 | 
						|
      if ((*p & 0x3B000000) == 0x39000000) { // << load / store
 | 
						|
        // For load / store instructions the size is encoded in bits 31:30.
 | 
						|
        ImplicitShift = ((*p >> 30) & 0x3);
 | 
						|
        if (ImplicitShift == 0) {
 | 
						|
          // Check if this a vector op to get the correct shift value.
 | 
						|
          if ((*p & 0x04800000) == 0x04800000)
 | 
						|
            ImplicitShift = 4;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      // Compensate for implicit shift.
 | 
						|
      Addend <<= ImplicitShift;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    }
 | 
						|
    return Addend;
 | 
						|
  }
 | 
						|
 | 
						|
  /// Extract the addend encoded in the instruction.
 | 
						|
  void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes,
 | 
						|
                    MachO::RelocationInfoType RelType, int64_t Addend) const {
 | 
						|
    // Verify that the relocation has the correct alignment.
 | 
						|
    switch (RelType) {
 | 
						|
    default:
 | 
						|
      llvm_unreachable("Unsupported relocation type!");
 | 
						|
    case MachO::ARM64_RELOC_POINTER_TO_GOT:
 | 
						|
    case MachO::ARM64_RELOC_UNSIGNED:
 | 
						|
      assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
 | 
						|
      break;
 | 
						|
    case MachO::ARM64_RELOC_BRANCH26:
 | 
						|
    case MachO::ARM64_RELOC_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_PAGEOFF12:
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
 | 
						|
      assert(NumBytes == 4 && "Invalid relocation size.");
 | 
						|
      assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
 | 
						|
             "Instruction address is not aligned to 4 bytes.");
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (RelType) {
 | 
						|
    default:
 | 
						|
      llvm_unreachable("Unsupported relocation type!");
 | 
						|
    case MachO::ARM64_RELOC_POINTER_TO_GOT:
 | 
						|
    case MachO::ARM64_RELOC_UNSIGNED:
 | 
						|
      // This could be an unaligned memory location.
 | 
						|
      if (NumBytes == 4)
 | 
						|
        *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend;
 | 
						|
      else
 | 
						|
        *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend;
 | 
						|
      break;
 | 
						|
    case MachO::ARM64_RELOC_BRANCH26: {
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      // Verify that the relocation points to the expected branch instruction.
 | 
						|
      assert(((*p & 0xFC000000) == 0x14000000 ||
 | 
						|
              (*p & 0xFC000000) == 0x94000000) &&
 | 
						|
             "Expected branch instruction.");
 | 
						|
 | 
						|
      // Verify addend value.
 | 
						|
      assert((Addend & 0x3) == 0 && "Branch target is not aligned");
 | 
						|
      assert(isInt<28>(Addend) && "Branch target is out of range.");
 | 
						|
 | 
						|
      // Encode the addend as 26 bit immediate in the branch instruction.
 | 
						|
      *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_PAGE21: {
 | 
						|
      // Verify that the relocation points to the expected adrp instruction.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
 | 
						|
 | 
						|
      // Check that the addend fits into 21 bits (+ 12 lower bits).
 | 
						|
      assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
 | 
						|
      assert(isInt<33>(Addend) && "Invalid page reloc value.");
 | 
						|
 | 
						|
      // Encode the addend into the instruction.
 | 
						|
      uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000;
 | 
						|
      uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0;
 | 
						|
      *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
 | 
						|
      // Verify that the relocation points to one of the expected load / store
 | 
						|
      // instructions.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      assert((*p & 0x3B000000) == 0x39000000 &&
 | 
						|
             "Only expected load / store instructions.");
 | 
						|
      (void)p;
 | 
						|
      LLVM_FALLTHROUGH;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_PAGEOFF12: {
 | 
						|
      // Verify that the relocation points to one of the expected load / store
 | 
						|
      // or add / sub instructions.
 | 
						|
      auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
 | 
						|
      assert((((*p & 0x3B000000) == 0x39000000) ||
 | 
						|
              ((*p & 0x11C00000) == 0x11000000)   ) &&
 | 
						|
             "Expected load / store  or add/sub instruction.");
 | 
						|
 | 
						|
      // Check which instruction we are decoding to obtain the implicit shift
 | 
						|
      // factor of the instruction and verify alignment.
 | 
						|
      int ImplicitShift = 0;
 | 
						|
      if ((*p & 0x3B000000) == 0x39000000) { // << load / store
 | 
						|
        // For load / store instructions the size is encoded in bits 31:30.
 | 
						|
        ImplicitShift = ((*p >> 30) & 0x3);
 | 
						|
        switch (ImplicitShift) {
 | 
						|
        case 0:
 | 
						|
          // Check if this a vector op to get the correct shift value.
 | 
						|
          if ((*p & 0x04800000) == 0x04800000) {
 | 
						|
            ImplicitShift = 4;
 | 
						|
            assert(((Addend & 0xF) == 0) &&
 | 
						|
                   "128-bit LDR/STR not 16-byte aligned.");
 | 
						|
          }
 | 
						|
          break;
 | 
						|
        case 1:
 | 
						|
          assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
 | 
						|
          break;
 | 
						|
        case 2:
 | 
						|
          assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
 | 
						|
          break;
 | 
						|
        case 3:
 | 
						|
          assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      // Compensate for implicit shift.
 | 
						|
      Addend >>= ImplicitShift;
 | 
						|
      assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
 | 
						|
 | 
						|
      // Encode the addend into the instruction.
 | 
						|
      *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Expected<relocation_iterator>
 | 
						|
  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
 | 
						|
                       const ObjectFile &BaseObjT,
 | 
						|
                       ObjSectionToIDMap &ObjSectionToID,
 | 
						|
                       StubMap &Stubs) override {
 | 
						|
    const MachOObjectFile &Obj =
 | 
						|
      static_cast<const MachOObjectFile &>(BaseObjT);
 | 
						|
    MachO::any_relocation_info RelInfo =
 | 
						|
        Obj.getRelocation(RelI->getRawDataRefImpl());
 | 
						|
 | 
						|
    if (Obj.isRelocationScattered(RelInfo))
 | 
						|
      return make_error<RuntimeDyldError>("Scattered relocations not supported "
 | 
						|
                                          "for MachO AArch64");
 | 
						|
 | 
						|
    // 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.
 | 
						|
    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);
 | 
						|
      int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
 | 
						|
      // Sign-extend the 24-bit to 64-bit.
 | 
						|
      ExplicitAddend = SignExtend64(RawAddend, 24);
 | 
						|
      ++RelI;
 | 
						|
      RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
 | 
						|
    }
 | 
						|
 | 
						|
    if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR)
 | 
						|
      return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
 | 
						|
 | 
						|
    RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
 | 
						|
 | 
						|
    if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
 | 
						|
      bool Valid =
 | 
						|
          (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel);
 | 
						|
      if (!Valid)
 | 
						|
        return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports "
 | 
						|
                                       "32-bit pc-rel or 64-bit absolute only",
 | 
						|
                                       inconvertibleErrorCode());
 | 
						|
    }
 | 
						|
 | 
						|
    if (auto Addend = decodeAddend(RE))
 | 
						|
      RE.Addend = *Addend;
 | 
						|
    else
 | 
						|
      return Addend.takeError();
 | 
						|
 | 
						|
    assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
 | 
						|
      "ARM64_RELOC_ADDEND and embedded addend in the instruction.");
 | 
						|
    if (ExplicitAddend)
 | 
						|
      RE.Addend = ExplicitAddend;
 | 
						|
 | 
						|
    RelocationValueRef Value;
 | 
						|
    if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
 | 
						|
      Value = *ValueOrErr;
 | 
						|
    else
 | 
						|
      return ValueOrErr.takeError();
 | 
						|
 | 
						|
    bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
 | 
						|
    if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
 | 
						|
      // We'll take care of the offset in processGOTRelocation.
 | 
						|
      Value.Offset = 0;
 | 
						|
    } else if (!IsExtern && RE.IsPCRel)
 | 
						|
      makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
 | 
						|
 | 
						|
    RE.Addend = Value.Offset;
 | 
						|
 | 
						|
    if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
 | 
						|
        RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 ||
 | 
						|
        RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT)
 | 
						|
      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) override {
 | 
						|
    LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
 | 
						|
 | 
						|
    const SectionEntry &Section = Sections[RE.SectionID];
 | 
						|
    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
 | 
						|
    MachO::RelocationInfoType RelType =
 | 
						|
      static_cast<MachO::RelocationInfoType>(RE.RelType);
 | 
						|
 | 
						|
    switch (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");
 | 
						|
 | 
						|
      encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case MachO::ARM64_RELOC_POINTER_TO_GOT: {
 | 
						|
      assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) &&
 | 
						|
             "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit "
 | 
						|
             "absolute");
 | 
						|
      // Addend is the GOT entry address and RE.Offset the target of the
 | 
						|
      // relocation.
 | 
						|
      uint64_t Result =
 | 
						|
          RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend);
 | 
						|
      encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case MachO::ARM64_RELOC_BRANCH26: {
 | 
						|
      assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
 | 
						|
      // Check if branch is in range.
 | 
						|
      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
 | 
						|
      int64_t PCRelVal = Value - FinalAddress + RE.Addend;
 | 
						|
      encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_PAGE21: {
 | 
						|
      assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
 | 
						|
      // Adjust for PC-relative relocation and offset.
 | 
						|
      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
 | 
						|
      int64_t PCRelVal =
 | 
						|
        ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
 | 
						|
      encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
 | 
						|
    case MachO::ARM64_RELOC_PAGEOFF12: {
 | 
						|
      assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
 | 
						|
      // Add the offset from the symbol.
 | 
						|
      Value += RE.Addend;
 | 
						|
      // Mask out the page address and only use the lower 12 bits.
 | 
						|
      Value &= 0xFFF;
 | 
						|
      encodeAddend(LocalAddress, /*Size=*/4, RelType, Value);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case MachO::ARM64_RELOC_SUBTRACTOR: {
 | 
						|
      uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
 | 
						|
      uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
 | 
						|
      assert((Value == SectionABase || Value == SectionBBase) &&
 | 
						|
             "Unexpected SUBTRACTOR relocation value.");
 | 
						|
      Value = SectionABase - SectionBBase + RE.Addend;
 | 
						|
      writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
 | 
						|
    case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
 | 
						|
      llvm_unreachable("Relocation type not yet implemented!");
 | 
						|
    case MachO::ARM64_RELOC_ADDEND:
 | 
						|
      llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
 | 
						|
                       "processRelocationRef!");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
 | 
						|
                       const SectionRef &Section) {
 | 
						|
    return Error::success();
 | 
						|
  }
 | 
						|
 | 
						|
private:
 | 
						|
  void processGOTRelocation(const RelocationEntry &RE,
 | 
						|
                            RelocationValueRef &Value, StubMap &Stubs) {
 | 
						|
    assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT &&
 | 
						|
            (RE.Size == 2 || RE.Size == 3)) ||
 | 
						|
           RE.Size == 2);
 | 
						|
    SectionEntry &Section = Sections[RE.SectionID];
 | 
						|
    StubMap::const_iterator i = Stubs.find(Value);
 | 
						|
    int64_t Offset;
 | 
						|
    if (i != Stubs.end())
 | 
						|
      Offset = static_cast<int64_t>(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.getAddress());
 | 
						|
      uintptr_t StubAlignment = getStubAlignment();
 | 
						|
      uintptr_t StubAddress =
 | 
						|
          (BaseAddress + Section.getStubOffset() + 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.Offset,
 | 
						|
                            /*IsPCRel=*/false, /*Size=*/3);
 | 
						|
      if (Value.SymbolName)
 | 
						|
        addRelocationForSymbol(GOTRE, Value.SymbolName);
 | 
						|
      else
 | 
						|
        addRelocationForSection(GOTRE, Value.SectionID);
 | 
						|
      Section.advanceStubOffset(getMaxStubSize());
 | 
						|
      Offset = static_cast<int64_t>(StubOffset);
 | 
						|
    }
 | 
						|
    RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset,
 | 
						|
                             RE.IsPCRel, RE.Size);
 | 
						|
    addRelocationForSection(TargetRE, RE.SectionID);
 | 
						|
  }
 | 
						|
 | 
						|
  Expected<relocation_iterator>
 | 
						|
  processSubtractRelocation(unsigned SectionID, relocation_iterator RelI,
 | 
						|
                            const ObjectFile &BaseObjT,
 | 
						|
                            ObjSectionToIDMap &ObjSectionToID) {
 | 
						|
    const MachOObjectFile &Obj =
 | 
						|
        static_cast<const MachOObjectFile&>(BaseObjT);
 | 
						|
    MachO::any_relocation_info RE =
 | 
						|
        Obj.getRelocation(RelI->getRawDataRefImpl());
 | 
						|
 | 
						|
    unsigned Size = Obj.getAnyRelocationLength(RE);
 | 
						|
    uint64_t Offset = RelI->getOffset();
 | 
						|
    uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset);
 | 
						|
    unsigned NumBytes = 1 << Size;
 | 
						|
 | 
						|
    Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName();
 | 
						|
    if (!SubtrahendNameOrErr)
 | 
						|
      return SubtrahendNameOrErr.takeError();
 | 
						|
    auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr);
 | 
						|
    unsigned SectionBID = SubtrahendI->second.getSectionID();
 | 
						|
    uint64_t SectionBOffset = SubtrahendI->second.getOffset();
 | 
						|
    int64_t Addend =
 | 
						|
      SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8);
 | 
						|
 | 
						|
    ++RelI;
 | 
						|
    Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName();
 | 
						|
    if (!MinuendNameOrErr)
 | 
						|
      return MinuendNameOrErr.takeError();
 | 
						|
    auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr);
 | 
						|
    unsigned SectionAID = MinuendI->second.getSectionID();
 | 
						|
    uint64_t SectionAOffset = MinuendI->second.getOffset();
 | 
						|
 | 
						|
    RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend,
 | 
						|
                      SectionAID, SectionAOffset, SectionBID, SectionBOffset,
 | 
						|
                      false, Size);
 | 
						|
 | 
						|
    addRelocationForSection(R, SectionAID);
 | 
						|
 | 
						|
    return ++RelI;
 | 
						|
  }
 | 
						|
 | 
						|
  static const char *getRelocName(uint32_t RelocType) {
 | 
						|
    switch (RelocType) {
 | 
						|
      case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED";
 | 
						|
      case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR";
 | 
						|
      case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26";
 | 
						|
      case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21";
 | 
						|
      case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12";
 | 
						|
      case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21";
 | 
						|
      case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12";
 | 
						|
      case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT";
 | 
						|
      case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21";
 | 
						|
      case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12";
 | 
						|
      case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND";
 | 
						|
    }
 | 
						|
    return "Unrecognized arm64 addend";
 | 
						|
  }
 | 
						|
 | 
						|
};
 | 
						|
}
 | 
						|
 | 
						|
#undef DEBUG_TYPE
 | 
						|
 | 
						|
#endif
 |