1 //===---- aarch64.cpp - Generic JITLink aarch64 edge kinds, utilities -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Generic utilities for graphs representing aarch64 objects. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/aarch64.h" 14 15 #define DEBUG_TYPE "jitlink" 16 17 namespace llvm { 18 namespace jitlink { 19 namespace aarch64 { 20 21 bool isLoadStoreImm12(uint32_t Instr) { 22 constexpr uint32_t LoadStoreImm12Mask = 0x3b000000; 23 return (Instr & LoadStoreImm12Mask) == 0x39000000; 24 } 25 26 unsigned getPageOffset12Shift(uint32_t Instr) { 27 constexpr uint32_t Vec128Mask = 0x04800000; 28 29 if (isLoadStoreImm12(Instr)) { 30 uint32_t ImplicitShift = Instr >> 30; 31 if (ImplicitShift == 0) 32 if ((Instr & Vec128Mask) == Vec128Mask) 33 ImplicitShift = 4; 34 35 return ImplicitShift; 36 } 37 38 return 0; 39 } 40 41 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) { 42 using namespace support; 43 44 char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 45 char *FixupPtr = BlockWorkingMem + E.getOffset(); 46 orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset(); 47 48 switch (E.getKind()) { 49 case Branch26: { 50 assert((FixupAddress.getValue() & 0x3) == 0 && 51 "Branch-inst is not 32-bit aligned"); 52 53 int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 54 55 if (static_cast<uint64_t>(Value) & 0x3) 56 return make_error<JITLinkError>("Branch26 target is not 32-bit " 57 "aligned"); 58 59 if (Value < -(1 << 27) || Value > ((1 << 27) - 1)) 60 return makeTargetOutOfRangeError(G, B, E); 61 62 uint32_t RawInstr = *(little32_t *)FixupPtr; 63 assert((RawInstr & 0x7fffffff) == 0x14000000 && 64 "RawInstr isn't a B or BR immediate instruction"); 65 uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2; 66 uint32_t FixedInstr = RawInstr | Imm; 67 *(little32_t *)FixupPtr = FixedInstr; 68 break; 69 } 70 case Pointer32: { 71 uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 72 if (Value > std::numeric_limits<uint32_t>::max()) 73 return makeTargetOutOfRangeError(G, B, E); 74 *(ulittle32_t *)FixupPtr = Value; 75 break; 76 } 77 case Pointer64: 78 case Pointer64Anon: { 79 uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 80 *(ulittle64_t *)FixupPtr = Value; 81 break; 82 } 83 case Page21: 84 case TLVPage21: 85 case GOTPage21: { 86 assert((E.getKind() != GOTPage21 || E.getAddend() == 0) && 87 "GOTPAGE21 with non-zero addend"); 88 uint64_t TargetPage = 89 (E.getTarget().getAddress().getValue() + E.getAddend()) & 90 ~static_cast<uint64_t>(4096 - 1); 91 uint64_t PCPage = 92 FixupAddress.getValue() & ~static_cast<uint64_t>(4096 - 1); 93 94 int64_t PageDelta = TargetPage - PCPage; 95 if (!isInt<33>(PageDelta)) 96 return makeTargetOutOfRangeError(G, B, E); 97 98 uint32_t RawInstr = *(ulittle32_t *)FixupPtr; 99 assert((RawInstr & 0xffffffe0) == 0x90000000 && 100 "RawInstr isn't an ADRP instruction"); 101 uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3; 102 uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff; 103 uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5); 104 *(ulittle32_t *)FixupPtr = FixedInstr; 105 break; 106 } 107 case PageOffset12: { 108 uint64_t TargetOffset = 109 (E.getTarget().getAddress() + E.getAddend()).getValue() & 0xfff; 110 111 uint32_t RawInstr = *(ulittle32_t *)FixupPtr; 112 unsigned ImmShift = getPageOffset12Shift(RawInstr); 113 114 if (TargetOffset & ((1 << ImmShift) - 1)) 115 return make_error<JITLinkError>("PAGEOFF12 target is not aligned"); 116 117 uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10; 118 uint32_t FixedInstr = RawInstr | EncodedImm; 119 *(ulittle32_t *)FixupPtr = FixedInstr; 120 break; 121 } 122 case TLVPageOffset12: 123 case GOTPageOffset12: { 124 assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend"); 125 126 uint32_t RawInstr = *(ulittle32_t *)FixupPtr; 127 assert((RawInstr & 0xfffffc00) == 0xf9400000 && 128 "RawInstr isn't a 64-bit LDR immediate"); 129 130 uint32_t TargetOffset = E.getTarget().getAddress().getValue() & 0xfff; 131 assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned"); 132 uint32_t EncodedImm = (TargetOffset >> 3) << 10; 133 uint32_t FixedInstr = RawInstr | EncodedImm; 134 *(ulittle32_t *)FixupPtr = FixedInstr; 135 break; 136 } 137 case LDRLiteral19: { 138 assert((FixupAddress.getValue() & 0x3) == 0 && "LDR is not 32-bit aligned"); 139 assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend"); 140 uint32_t RawInstr = *(ulittle32_t *)FixupPtr; 141 assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal"); 142 int64_t Delta = E.getTarget().getAddress() - FixupAddress; 143 if (Delta & 0x3) 144 return make_error<JITLinkError>("LDR literal target is not 32-bit " 145 "aligned"); 146 if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1)) 147 return makeTargetOutOfRangeError(G, B, E); 148 149 uint32_t EncodedImm = ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5; 150 uint32_t FixedInstr = RawInstr | EncodedImm; 151 *(ulittle32_t *)FixupPtr = FixedInstr; 152 break; 153 } 154 case Delta32: 155 case Delta64: 156 case NegDelta32: 157 case NegDelta64: { 158 int64_t Value; 159 if (E.getKind() == Delta32 || E.getKind() == Delta64) 160 Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 161 else 162 Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); 163 164 if (E.getKind() == Delta32 || E.getKind() == NegDelta32) { 165 if (Value < std::numeric_limits<int32_t>::min() || 166 Value > std::numeric_limits<int32_t>::max()) 167 return makeTargetOutOfRangeError(G, B, E); 168 *(little32_t *)FixupPtr = Value; 169 } else 170 *(little64_t *)FixupPtr = Value; 171 break; 172 } 173 default: 174 return make_error<JITLinkError>( 175 "In graph " + G.getName() + ", section " + B.getSection().getName() + 176 "unsupported edge kind" + getEdgeKindName(E.getKind())); 177 } 178 179 return Error::success(); 180 } 181 182 const char *getEdgeKindName(Edge::Kind R) { 183 switch (R) { 184 case Branch26: 185 return "Branch26"; 186 case Pointer64: 187 return "Pointer64"; 188 case Pointer64Anon: 189 return "Pointer64Anon"; 190 case Page21: 191 return "Page21"; 192 case PageOffset12: 193 return "PageOffset12"; 194 case GOTPage21: 195 return "GOTPage21"; 196 case GOTPageOffset12: 197 return "GOTPageOffset12"; 198 case TLVPage21: 199 return "TLVPage21"; 200 case TLVPageOffset12: 201 return "TLVPageOffset12"; 202 case PointerToGOT: 203 return "PointerToGOT"; 204 case PairedAddend: 205 return "PairedAddend"; 206 case LDRLiteral19: 207 return "LDRLiteral19"; 208 case Delta32: 209 return "Delta32"; 210 case Delta64: 211 return "Delta64"; 212 case NegDelta32: 213 return "NegDelta32"; 214 case NegDelta64: 215 return "NegDelta64"; 216 default: 217 return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); 218 } 219 } 220 221 } // namespace aarch64 222 } // namespace jitlink 223 } // namespace llvm 224