1*06c3fb27SDimitry Andric //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric // 9*06c3fb27SDimitry Andric // Generic utilities for graphs representing arm/thumb objects. 10*06c3fb27SDimitry Andric // 11*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 12*06c3fb27SDimitry Andric 13*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch32.h" 14*06c3fb27SDimitry Andric 15*06c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 16*06c3fb27SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 17*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 18*06c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 19*06c3fb27SDimitry Andric #include "llvm/Support/Endian.h" 20*06c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h" 21*06c3fb27SDimitry Andric 22*06c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink" 23*06c3fb27SDimitry Andric 24*06c3fb27SDimitry Andric namespace llvm { 25*06c3fb27SDimitry Andric namespace jitlink { 26*06c3fb27SDimitry Andric namespace aarch32 { 27*06c3fb27SDimitry Andric 28*06c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range 29*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 30*06c3fb27SDimitry Andric /// 31*06c3fb27SDimitry Andric /// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ] 32*06c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 33*06c3fb27SDimitry Andric /// 34*06c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) { 35*06c3fb27SDimitry Andric constexpr uint32_t J1J2 = 0x2800; 36*06c3fb27SDimitry Andric uint32_t Imm11H = (Value >> 12) & 0x07ff; 37*06c3fb27SDimitry Andric uint32_t Imm11L = (Value >> 1) & 0x07ff; 38*06c3fb27SDimitry Andric return HalfWords{Imm11H, Imm11L | J1J2}; 39*06c3fb27SDimitry Andric } 40*06c3fb27SDimitry Andric 41*06c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range 42*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 43*06c3fb27SDimitry Andric /// 44*06c3fb27SDimitry Andric /// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0 45*06c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 46*06c3fb27SDimitry Andric /// 47*06c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) { 48*06c3fb27SDimitry Andric uint32_t Imm11H = Hi & 0x07ff; 49*06c3fb27SDimitry Andric uint32_t Imm11L = Lo & 0x07ff; 50*06c3fb27SDimitry Andric return SignExtend64<22>(Imm11H << 12 | Imm11L << 1); 51*06c3fb27SDimitry Andric } 52*06c3fb27SDimitry Andric 53*06c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range 54*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 55*06c3fb27SDimitry Andric /// 56*06c3fb27SDimitry Andric /// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ] 57*06c3fb27SDimitry Andric /// 58*06c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) { 59*06c3fb27SDimitry Andric uint32_t S = (Value >> 14) & 0x0400; 60*06c3fb27SDimitry Andric uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000); 61*06c3fb27SDimitry Andric uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800); 62*06c3fb27SDimitry Andric uint32_t Imm10 = (Value >> 12) & 0x03ff; 63*06c3fb27SDimitry Andric uint32_t Imm11 = (Value >> 1) & 0x07ff; 64*06c3fb27SDimitry Andric return HalfWords{S | Imm10, J1 | J2 | Imm11}; 65*06c3fb27SDimitry Andric } 66*06c3fb27SDimitry Andric 67*06c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range 68*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 69*06c3fb27SDimitry Andric /// 70*06c3fb27SDimitry Andric /// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0 71*06c3fb27SDimitry Andric /// 72*06c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) { 73*06c3fb27SDimitry Andric uint32_t S = Hi & 0x0400; 74*06c3fb27SDimitry Andric uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000; 75*06c3fb27SDimitry Andric uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000; 76*06c3fb27SDimitry Andric uint32_t Imm10 = Hi & 0x03ff; 77*06c3fb27SDimitry Andric uint32_t Imm11 = Lo & 0x07ff; 78*06c3fb27SDimitry Andric return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1); 79*06c3fb27SDimitry Andric } 80*06c3fb27SDimitry Andric 81*06c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and 82*06c3fb27SDimitry Andric /// MOVW T3. 83*06c3fb27SDimitry Andric /// 84*06c3fb27SDimitry Andric /// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] 85*06c3fb27SDimitry Andric /// 86*06c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) { 87*06c3fb27SDimitry Andric uint32_t Imm4 = (Value >> 12) & 0x0f; 88*06c3fb27SDimitry Andric uint32_t Imm1 = (Value >> 11) & 0x01; 89*06c3fb27SDimitry Andric uint32_t Imm3 = (Value >> 8) & 0x07; 90*06c3fb27SDimitry Andric uint32_t Imm8 = Value & 0xff; 91*06c3fb27SDimitry Andric return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8}; 92*06c3fb27SDimitry Andric } 93*06c3fb27SDimitry Andric 94*06c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and 95*06c3fb27SDimitry Andric /// MOVW T3. 96*06c3fb27SDimitry Andric /// 97*06c3fb27SDimitry Andric /// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8 98*06c3fb27SDimitry Andric /// 99*06c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 100*06c3fb27SDimitry Andric uint32_t Imm4 = Hi & 0x0f; 101*06c3fb27SDimitry Andric uint32_t Imm1 = (Hi >> 10) & 0x01; 102*06c3fb27SDimitry Andric uint32_t Imm3 = (Lo >> 12) & 0x07; 103*06c3fb27SDimitry Andric uint32_t Imm8 = Lo & 0xff; 104*06c3fb27SDimitry Andric uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8; 105*06c3fb27SDimitry Andric assert(Imm16 <= 0xffff && "Decoded value out-of-range"); 106*06c3fb27SDimitry Andric return Imm16; 107*06c3fb27SDimitry Andric } 108*06c3fb27SDimitry Andric 109*06c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3. 110*06c3fb27SDimitry Andric /// 111*06c3fb27SDimitry Andric /// Rd4 -> [0000000000000000, 0000:Rd4:00000000] 112*06c3fb27SDimitry Andric /// 113*06c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) { 114*06c3fb27SDimitry Andric uint32_t Rd4 = (Value & 0x0f) << 8; 115*06c3fb27SDimitry Andric return HalfWords{0, Rd4}; 116*06c3fb27SDimitry Andric } 117*06c3fb27SDimitry Andric 118*06c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3. 119*06c3fb27SDimitry Andric /// 120*06c3fb27SDimitry Andric /// [0000000000000000, 0000:Rd4:00000000] -> Rd4 121*06c3fb27SDimitry Andric /// 122*06c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 123*06c3fb27SDimitry Andric uint32_t Rd4 = (Lo >> 8) & 0x0f; 124*06c3fb27SDimitry Andric return Rd4; 125*06c3fb27SDimitry Andric } 126*06c3fb27SDimitry Andric 127*06c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords. 128*06c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi), 129*06c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo). 130*06c3fb27SDimitry Andric struct WritableThumbRelocation { 131*06c3fb27SDimitry Andric /// Create a writable reference to a Thumb32 fixup. 132*06c3fb27SDimitry Andric WritableThumbRelocation(char *FixupPtr) 133*06c3fb27SDimitry Andric : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)}, 134*06c3fb27SDimitry Andric Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {} 135*06c3fb27SDimitry Andric 136*06c3fb27SDimitry Andric support::ulittle16_t &Hi; // First halfword 137*06c3fb27SDimitry Andric support::ulittle16_t &Lo; // Second halfword 138*06c3fb27SDimitry Andric }; 139*06c3fb27SDimitry Andric 140*06c3fb27SDimitry Andric struct ThumbRelocation { 141*06c3fb27SDimitry Andric /// Create a read-only reference to a Thumb32 fixup. 142*06c3fb27SDimitry Andric ThumbRelocation(const char *FixupPtr) 143*06c3fb27SDimitry Andric : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)}, 144*06c3fb27SDimitry Andric Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {} 145*06c3fb27SDimitry Andric 146*06c3fb27SDimitry Andric /// Create a read-only Thumb32 fixup from a writeable one. 147*06c3fb27SDimitry Andric ThumbRelocation(WritableThumbRelocation &Writable) 148*06c3fb27SDimitry Andric : Hi{Writable.Hi}, Lo(Writable.Lo) {} 149*06c3fb27SDimitry Andric 150*06c3fb27SDimitry Andric const support::ulittle16_t &Hi; // First halfword 151*06c3fb27SDimitry Andric const support::ulittle16_t &Lo; // Second halfword 152*06c3fb27SDimitry Andric }; 153*06c3fb27SDimitry Andric 154*06c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, 155*06c3fb27SDimitry Andric Edge::Kind Kind) { 156*06c3fb27SDimitry Andric return make_error<JITLinkError>( 157*06c3fb27SDimitry Andric formatv("Invalid opcode [ 0x{0:x4}, 0x{1:x4} ] for relocation: {2}", 158*06c3fb27SDimitry Andric static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo), 159*06c3fb27SDimitry Andric G.getEdgeKindName(Kind))); 160*06c3fb27SDimitry Andric } 161*06c3fb27SDimitry Andric 162*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> bool checkOpcode(const ThumbRelocation &R) { 163*06c3fb27SDimitry Andric uint16_t Hi = R.Hi & FixupInfo<Kind>::OpcodeMask.Hi; 164*06c3fb27SDimitry Andric uint16_t Lo = R.Lo & FixupInfo<Kind>::OpcodeMask.Lo; 165*06c3fb27SDimitry Andric return Hi == FixupInfo<Kind>::Opcode.Hi && Lo == FixupInfo<Kind>::Opcode.Lo; 166*06c3fb27SDimitry Andric } 167*06c3fb27SDimitry Andric 168*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 169*06c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) { 170*06c3fb27SDimitry Andric uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi; 171*06c3fb27SDimitry Andric uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo; 172*06c3fb27SDimitry Andric return Hi == Reg.Hi && Lo == Reg.Lo; 173*06c3fb27SDimitry Andric } 174*06c3fb27SDimitry Andric 175*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 176*06c3fb27SDimitry Andric bool writeRegister(WritableThumbRelocation &R, HalfWords Reg) { 177*06c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask; 178*06c3fb27SDimitry Andric assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Hi & Reg.Hi) == Reg.Hi && 179*06c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 180*06c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi; 181*06c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo; 182*06c3fb27SDimitry Andric } 183*06c3fb27SDimitry Andric 184*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 185*06c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) { 186*06c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask; 187*06c3fb27SDimitry Andric assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Hi & Imm.Hi) == Imm.Hi && 188*06c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 189*06c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi; 190*06c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo; 191*06c3fb27SDimitry Andric } 192*06c3fb27SDimitry Andric 193*06c3fb27SDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E) { 194*06c3fb27SDimitry Andric support::endianness Endian = G.getEndianness(); 195*06c3fb27SDimitry Andric assert(Endian != support::native && "Declare as little or big explicitly"); 196*06c3fb27SDimitry Andric 197*06c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 198*06c3fb27SDimitry Andric const char *BlockWorkingMem = B.getContent().data(); 199*06c3fb27SDimitry Andric const char *FixupPtr = BlockWorkingMem + E.getOffset(); 200*06c3fb27SDimitry Andric 201*06c3fb27SDimitry Andric switch (Kind) { 202*06c3fb27SDimitry Andric case Data_Delta32: 203*06c3fb27SDimitry Andric case Data_Pointer32: 204*06c3fb27SDimitry Andric return SignExtend64<32>(support::endian::read32(FixupPtr, Endian)); 205*06c3fb27SDimitry Andric default: 206*06c3fb27SDimitry Andric return make_error<JITLinkError>( 207*06c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 208*06c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 209*06c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 210*06c3fb27SDimitry Andric } 211*06c3fb27SDimitry Andric } 212*06c3fb27SDimitry Andric 213*06c3fb27SDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) { 214*06c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 215*06c3fb27SDimitry Andric 216*06c3fb27SDimitry Andric switch (Kind) { 217*06c3fb27SDimitry Andric case Arm_Call: 218*06c3fb27SDimitry Andric return make_error<JITLinkError>( 219*06c3fb27SDimitry Andric "Addend extraction for relocation type not yet implemented: " + 220*06c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 221*06c3fb27SDimitry Andric default: 222*06c3fb27SDimitry Andric return make_error<JITLinkError>( 223*06c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 224*06c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 225*06c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 226*06c3fb27SDimitry Andric } 227*06c3fb27SDimitry Andric } 228*06c3fb27SDimitry Andric 229*06c3fb27SDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E, 230*06c3fb27SDimitry Andric const ArmConfig &ArmCfg) { 231*06c3fb27SDimitry Andric ThumbRelocation R(B.getContent().data() + E.getOffset()); 232*06c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 233*06c3fb27SDimitry Andric 234*06c3fb27SDimitry Andric switch (Kind) { 235*06c3fb27SDimitry Andric case Thumb_Call: 236*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_Call>(R)) 237*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 238*06c3fb27SDimitry Andric return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 239*06c3fb27SDimitry Andric ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 240*06c3fb27SDimitry Andric : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 241*06c3fb27SDimitry Andric 242*06c3fb27SDimitry Andric case Thumb_Jump24: 243*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_Jump24>(R)) 244*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 245*06c3fb27SDimitry Andric if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional) 246*06c3fb27SDimitry Andric return make_error<JITLinkError>("Relocation expects an unconditional " 247*06c3fb27SDimitry Andric "B.W branch instruction: " + 248*06c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 249*06c3fb27SDimitry Andric return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 250*06c3fb27SDimitry Andric ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 251*06c3fb27SDimitry Andric : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 252*06c3fb27SDimitry Andric 253*06c3fb27SDimitry Andric case Thumb_MovwAbsNC: 254*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovwAbsNC>(R)) 255*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 256*06c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 257*06c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 258*06c3fb27SDimitry Andric 259*06c3fb27SDimitry Andric case Thumb_MovtAbs: 260*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovtAbs>(R)) 261*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 262*06c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 263*06c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 264*06c3fb27SDimitry Andric 265*06c3fb27SDimitry Andric default: 266*06c3fb27SDimitry Andric return make_error<JITLinkError>( 267*06c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 268*06c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 269*06c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 270*06c3fb27SDimitry Andric } 271*06c3fb27SDimitry Andric } 272*06c3fb27SDimitry Andric 273*06c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) { 274*06c3fb27SDimitry Andric using namespace support; 275*06c3fb27SDimitry Andric 276*06c3fb27SDimitry Andric char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 277*06c3fb27SDimitry Andric char *FixupPtr = BlockWorkingMem + E.getOffset(); 278*06c3fb27SDimitry Andric 279*06c3fb27SDimitry Andric auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) { 280*06c3fb27SDimitry Andric assert(Endian != native && "Must be explicit: little or big"); 281*06c3fb27SDimitry Andric assert(isInt<32>(Value) && "Must be in signed 32-bit range"); 282*06c3fb27SDimitry Andric uint32_t Imm = static_cast<int32_t>(Value); 283*06c3fb27SDimitry Andric if (LLVM_LIKELY(Endian == little)) 284*06c3fb27SDimitry Andric endian::write32<little>(FixupPtr, Imm); 285*06c3fb27SDimitry Andric else 286*06c3fb27SDimitry Andric endian::write32<big>(FixupPtr, Imm); 287*06c3fb27SDimitry Andric }; 288*06c3fb27SDimitry Andric 289*06c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 290*06c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 291*06c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 292*06c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 293*06c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 294*06c3fb27SDimitry Andric assert(!TargetSymbol.hasTargetFlags(ThumbSymbol)); 295*06c3fb27SDimitry Andric 296*06c3fb27SDimitry Andric // Regular data relocations have size 4, alignment 1 and write the full 32-bit 297*06c3fb27SDimitry Andric // result to the place; no need for overflow checking. There are three 298*06c3fb27SDimitry Andric // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31 299*06c3fb27SDimitry Andric switch (Kind) { 300*06c3fb27SDimitry Andric case Data_Delta32: { 301*06c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 302*06c3fb27SDimitry Andric if (!isInt<32>(Value)) 303*06c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 304*06c3fb27SDimitry Andric Write32(Value); 305*06c3fb27SDimitry Andric return Error::success(); 306*06c3fb27SDimitry Andric } 307*06c3fb27SDimitry Andric case Data_Pointer32: { 308*06c3fb27SDimitry Andric int64_t Value = TargetAddress + Addend; 309*06c3fb27SDimitry Andric if (!isInt<32>(Value)) 310*06c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 311*06c3fb27SDimitry Andric Write32(Value); 312*06c3fb27SDimitry Andric return Error::success(); 313*06c3fb27SDimitry Andric } 314*06c3fb27SDimitry Andric default: 315*06c3fb27SDimitry Andric return make_error<JITLinkError>( 316*06c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 317*06c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 318*06c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 319*06c3fb27SDimitry Andric } 320*06c3fb27SDimitry Andric } 321*06c3fb27SDimitry Andric 322*06c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) { 323*06c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 324*06c3fb27SDimitry Andric 325*06c3fb27SDimitry Andric switch (Kind) { 326*06c3fb27SDimitry Andric case Arm_Call: 327*06c3fb27SDimitry Andric return make_error<JITLinkError>( 328*06c3fb27SDimitry Andric "Fix-up for relocation type not yet implemented: " + 329*06c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 330*06c3fb27SDimitry Andric default: 331*06c3fb27SDimitry Andric return make_error<JITLinkError>( 332*06c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 333*06c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 334*06c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 335*06c3fb27SDimitry Andric } 336*06c3fb27SDimitry Andric } 337*06c3fb27SDimitry Andric 338*06c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, 339*06c3fb27SDimitry Andric const ArmConfig &ArmCfg) { 340*06c3fb27SDimitry Andric WritableThumbRelocation R(B.getAlreadyMutableContent().data() + 341*06c3fb27SDimitry Andric E.getOffset()); 342*06c3fb27SDimitry Andric 343*06c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 344*06c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 345*06c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 346*06c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 347*06c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 348*06c3fb27SDimitry Andric if (TargetSymbol.hasTargetFlags(ThumbSymbol)) 349*06c3fb27SDimitry Andric TargetAddress |= 0x01; 350*06c3fb27SDimitry Andric 351*06c3fb27SDimitry Andric switch (Kind) { 352*06c3fb27SDimitry Andric case Thumb_Jump24: { 353*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_Jump24>(R)) 354*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 355*06c3fb27SDimitry Andric if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional) 356*06c3fb27SDimitry Andric return make_error<JITLinkError>("Relocation expects an unconditional " 357*06c3fb27SDimitry Andric "B.W branch instruction: " + 358*06c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 359*06c3fb27SDimitry Andric if (!(TargetSymbol.hasTargetFlags(ThumbSymbol))) 360*06c3fb27SDimitry Andric return make_error<JITLinkError>("Branch relocation needs interworking " 361*06c3fb27SDimitry Andric "stub when bridging to ARM: " + 362*06c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 363*06c3fb27SDimitry Andric 364*06c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 365*06c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 366*06c3fb27SDimitry Andric if (!isInt<25>(Value)) 367*06c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 368*06c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 369*06c3fb27SDimitry Andric } else { 370*06c3fb27SDimitry Andric if (!isInt<22>(Value)) 371*06c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 372*06c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value)); 373*06c3fb27SDimitry Andric } 374*06c3fb27SDimitry Andric 375*06c3fb27SDimitry Andric return Error::success(); 376*06c3fb27SDimitry Andric } 377*06c3fb27SDimitry Andric 378*06c3fb27SDimitry Andric case Thumb_Call: { 379*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_Call>(R)) 380*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 381*06c3fb27SDimitry Andric 382*06c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 383*06c3fb27SDimitry Andric 384*06c3fb27SDimitry Andric // The call instruction itself is Thumb. The call destination can either be 385*06c3fb27SDimitry Andric // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm. 386*06c3fb27SDimitry Andric bool TargetIsArm = !TargetSymbol.hasTargetFlags(ThumbSymbol); 387*06c3fb27SDimitry Andric bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0; 388*06c3fb27SDimitry Andric if (TargetIsArm != InstrIsBlx) { 389*06c3fb27SDimitry Andric if (LLVM_LIKELY(TargetIsArm)) { 390*06c3fb27SDimitry Andric // Change opcode BL -> BLX and fix range value (account for 4-byte 391*06c3fb27SDimitry Andric // aligned destination while instruction may only be 2-byte aligned 392*06c3fb27SDimitry Andric // and clear Thumb bit). 393*06c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 394*06c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH; 395*06c3fb27SDimitry Andric Value = alignTo(Value, 4); 396*06c3fb27SDimitry Andric } else { 397*06c3fb27SDimitry Andric // Change opcode BLX -> BL and set Thumb bit 398*06c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 399*06c3fb27SDimitry Andric Value |= 0x01; 400*06c3fb27SDimitry Andric } 401*06c3fb27SDimitry Andric } 402*06c3fb27SDimitry Andric 403*06c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 404*06c3fb27SDimitry Andric if (!isInt<25>(Value)) 405*06c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 406*06c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 407*06c3fb27SDimitry Andric } else { 408*06c3fb27SDimitry Andric if (!isInt<22>(Value)) 409*06c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 410*06c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value)); 411*06c3fb27SDimitry Andric } 412*06c3fb27SDimitry Andric 413*06c3fb27SDimitry Andric assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) || 414*06c3fb27SDimitry Andric (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) && 415*06c3fb27SDimitry Andric "Opcode BLX implies H bit is clear (avoid UB in BLX T2)"); 416*06c3fb27SDimitry Andric return Error::success(); 417*06c3fb27SDimitry Andric } 418*06c3fb27SDimitry Andric 419*06c3fb27SDimitry Andric case Thumb_MovwAbsNC: { 420*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovwAbsNC>(R)) 421*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 422*06c3fb27SDimitry Andric uint16_t Value = (TargetAddress + Addend) & 0xffff; 423*06c3fb27SDimitry Andric writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value)); 424*06c3fb27SDimitry Andric return Error::success(); 425*06c3fb27SDimitry Andric } 426*06c3fb27SDimitry Andric 427*06c3fb27SDimitry Andric case Thumb_MovtAbs: { 428*06c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovtAbs>(R)) 429*06c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 430*06c3fb27SDimitry Andric uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 431*06c3fb27SDimitry Andric writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value)); 432*06c3fb27SDimitry Andric return Error::success(); 433*06c3fb27SDimitry Andric } 434*06c3fb27SDimitry Andric 435*06c3fb27SDimitry Andric default: 436*06c3fb27SDimitry Andric return make_error<JITLinkError>( 437*06c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 438*06c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 439*06c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 440*06c3fb27SDimitry Andric } 441*06c3fb27SDimitry Andric } 442*06c3fb27SDimitry Andric 443*06c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = { 444*06c3fb27SDimitry Andric 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit 445*06c3fb27SDimitry Andric 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit 446*06c3fb27SDimitry Andric 0x60, 0x47 // bx r12 447*06c3fb27SDimitry Andric }; 448*06c3fb27SDimitry Andric 449*06c3fb27SDimitry Andric template <> 450*06c3fb27SDimitry Andric Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) { 451*06c3fb27SDimitry Andric constexpr uint64_t Alignment = 4; 452*06c3fb27SDimitry Andric Block &B = addStub(G, Thumbv7ABS, Alignment); 453*06c3fb27SDimitry Andric LLVM_DEBUG({ 454*06c3fb27SDimitry Andric const char *StubPtr = B.getContent().data(); 455*06c3fb27SDimitry Andric HalfWords Reg12 = encodeRegMovtT1MovwT3(12); 456*06c3fb27SDimitry Andric assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && 457*06c3fb27SDimitry Andric checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && 458*06c3fb27SDimitry Andric "Linker generated stubs may only corrupt register r12 (IP)"); 459*06c3fb27SDimitry Andric }); 460*06c3fb27SDimitry Andric B.addEdge(Thumb_MovwAbsNC, 0, Target, 0); 461*06c3fb27SDimitry Andric B.addEdge(Thumb_MovtAbs, 4, Target, 0); 462*06c3fb27SDimitry Andric Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false); 463*06c3fb27SDimitry Andric Stub.setTargetFlags(ThumbSymbol); 464*06c3fb27SDimitry Andric return Stub; 465*06c3fb27SDimitry Andric } 466*06c3fb27SDimitry Andric 467*06c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) { 468*06c3fb27SDimitry Andric #define KIND_NAME_CASE(K) \ 469*06c3fb27SDimitry Andric case K: \ 470*06c3fb27SDimitry Andric return #K; 471*06c3fb27SDimitry Andric 472*06c3fb27SDimitry Andric switch (K) { 473*06c3fb27SDimitry Andric KIND_NAME_CASE(Data_Delta32) 474*06c3fb27SDimitry Andric KIND_NAME_CASE(Arm_Call) 475*06c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Call) 476*06c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Jump24) 477*06c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovwAbsNC) 478*06c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovtAbs) 479*06c3fb27SDimitry Andric default: 480*06c3fb27SDimitry Andric return getGenericEdgeKindName(K); 481*06c3fb27SDimitry Andric } 482*06c3fb27SDimitry Andric #undef KIND_NAME_CASE 483*06c3fb27SDimitry Andric } 484*06c3fb27SDimitry Andric 485*06c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) { 486*06c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K) \ 487*06c3fb27SDimitry Andric case K: \ 488*06c3fb27SDimitry Andric return #K; 489*06c3fb27SDimitry Andric 490*06c3fb27SDimitry Andric using namespace ARMBuildAttrs; 491*06c3fb27SDimitry Andric switch (K) { 492*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(Pre_v4) 493*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4) 494*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4T) 495*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5T) 496*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TE) 497*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TEJ) 498*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6) 499*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6KZ) 500*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6T2) 501*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6K) 502*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7) 503*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6_M) 504*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6S_M) 505*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7E_M) 506*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_A) 507*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_R) 508*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Base) 509*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Main) 510*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_1_M_Main) 511*06c3fb27SDimitry Andric CPUARCH_NAME_CASE(v9_A) 512*06c3fb27SDimitry Andric } 513*06c3fb27SDimitry Andric llvm_unreachable("Missing CPUArch in switch?"); 514*06c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE 515*06c3fb27SDimitry Andric } 516*06c3fb27SDimitry Andric 517*06c3fb27SDimitry Andric } // namespace aarch32 518*06c3fb27SDimitry Andric } // namespace jitlink 519*06c3fb27SDimitry Andric } // namespace llvm 520