[llvm] r212859 - [RuntimeDyld] Add GOT support for AArch64 to RuntimeDyldMachO.

David Blaikie dblaikie at gmail.com
Mon Jul 14 10:43:19 PDT 2014


On Fri, Jul 11, 2014 at 4:52 PM, Lang Hames <lhames at gmail.com> wrote:
> Author: lhames
> Date: Fri Jul 11 18:52:07 2014
> New Revision: 212859
>
> URL: http://llvm.org/viewvc/llvm-project?rev=212859&view=rev
> Log:
> [RuntimeDyld] Add GOT support for AArch64 to RuntimeDyldMachO.
>
> Test cases to follow once RuntimeDyldChecker supports introspection of stubs.
>
> Fixes <rdar://problem/17648000>
>
>
> Modified:
>     llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
>
> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp?rev=212859&r1=212858&r2=212859&view=diff
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp (original)
> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp Fri Jul 11 18:52:07 2014
> @@ -417,43 +417,124 @@ bool RuntimeDyldMachO::resolveAArch64Rel
>    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;
> -  }
> -
>    switch (RE.RelType) {
>    default:
>      llvm_unreachable("Invalid relocation type!");
> -  case MachO::ARM64_RELOC_UNSIGNED:
> -    return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
> +  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;
> -    // The low two bits of the value are not encoded.
> -    Value >>= 2;
> -    // Mask the value to 26 bits.
> -    uint64_t FinalValue = Value & 0x3ffffff;
> -    // Check for overflow.
> -    if (FinalValue != Value)
> -      return Error("ARM64 BRANCH26 relocation out of range.");
> +    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 & ~0x3ffffff) | FinalValue;
> +    *p = (*p & 0xFC000000) | ((uint32_t)(PCRelVal >> 2) & 0x03FFFFFF);
>      break;
>    }
> -  case MachO::ARM64_RELOC_SUBTRACTOR:
> -  case MachO::ARM64_RELOC_PAGE21:
> -  case MachO::ARM64_RELOC_PAGEOFF12:
>    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.");
> +    }

This /\ block looks like it should just be some asserts. We usually
avoid branching just to an unreachable (eg: "if (x) y() else
unreachable" would be written as "assert(x) y()")

assert((EncodedAddend == 0 || RE.Addend == 0) && "adrp instruction has
embedded addend.")
assert((EncodedAddend == 0 || RE.Addend != 0) && "adrp instruction has
embedded addend and ARM64_RELOC_ADDEND.")

Though I realize that means duplicating the conditions. I'd probably
just assert that EncodedAddend == 0 and leave it at that, using a
debugger to get the rest of the desired info. It makes the invariant
(EncodedAddend == 0) a little more obvious in the code, rather than
having to parse several lines of if block to realize that it's
actually an invariant.

> +    // 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:
> -  case MachO::ARM64_RELOC_ADDEND:
> +    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;
>  }
> @@ -659,8 +740,40 @@ relocation_iterator RuntimeDyldMachO::pr
>    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
> @@ -691,8 +804,11 @@ relocation_iterator RuntimeDyldMachO::pr
>    RelI->getOffset(Offset);
>    uint8_t *LocalAddress = Section.Address + Offset;
>    unsigned NumBytes = 1 << Size;
> -  uint64_t Addend = 0;
> -  memcpy(&Addend, LocalAddress, NumBytes);
> +  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
> @@ -793,7 +909,41 @@ relocation_iterator RuntimeDyldMachO::pr
>      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);
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list