[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