106c3fb27SDimitry Andric //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric // 906c3fb27SDimitry Andric // Generic utilities for graphs representing arm/thumb objects. 1006c3fb27SDimitry Andric // 1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch32.h" 1406c3fb27SDimitry Andric 1506c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 1606c3fb27SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 1706c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 1806c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 1906c3fb27SDimitry Andric #include "llvm/Support/Endian.h" 2006c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h" 2106c3fb27SDimitry Andric 2206c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink" 2306c3fb27SDimitry Andric 2406c3fb27SDimitry Andric namespace llvm { 2506c3fb27SDimitry Andric namespace jitlink { 2606c3fb27SDimitry Andric namespace aarch32 { 2706c3fb27SDimitry Andric 2806c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range 2906c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 3006c3fb27SDimitry Andric /// 3106c3fb27SDimitry Andric /// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ] 3206c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 3306c3fb27SDimitry Andric /// 3406c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) { 3506c3fb27SDimitry Andric constexpr uint32_t J1J2 = 0x2800; 3606c3fb27SDimitry Andric uint32_t Imm11H = (Value >> 12) & 0x07ff; 3706c3fb27SDimitry Andric uint32_t Imm11L = (Value >> 1) & 0x07ff; 3806c3fb27SDimitry Andric return HalfWords{Imm11H, Imm11L | J1J2}; 3906c3fb27SDimitry Andric } 4006c3fb27SDimitry Andric 4106c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range 4206c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 4306c3fb27SDimitry Andric /// 4406c3fb27SDimitry Andric /// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0 4506c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 4606c3fb27SDimitry Andric /// 4706c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) { 4806c3fb27SDimitry Andric uint32_t Imm11H = Hi & 0x07ff; 4906c3fb27SDimitry Andric uint32_t Imm11L = Lo & 0x07ff; 5006c3fb27SDimitry Andric return SignExtend64<22>(Imm11H << 12 | Imm11L << 1); 5106c3fb27SDimitry Andric } 5206c3fb27SDimitry Andric 5306c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range 5406c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 5506c3fb27SDimitry Andric /// 5606c3fb27SDimitry Andric /// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ] 5706c3fb27SDimitry Andric /// 5806c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) { 5906c3fb27SDimitry Andric uint32_t S = (Value >> 14) & 0x0400; 6006c3fb27SDimitry Andric uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000); 6106c3fb27SDimitry Andric uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800); 6206c3fb27SDimitry Andric uint32_t Imm10 = (Value >> 12) & 0x03ff; 6306c3fb27SDimitry Andric uint32_t Imm11 = (Value >> 1) & 0x07ff; 6406c3fb27SDimitry Andric return HalfWords{S | Imm10, J1 | J2 | Imm11}; 6506c3fb27SDimitry Andric } 6606c3fb27SDimitry Andric 6706c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range 6806c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 6906c3fb27SDimitry Andric /// 7006c3fb27SDimitry Andric /// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0 7106c3fb27SDimitry Andric /// 7206c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) { 7306c3fb27SDimitry Andric uint32_t S = Hi & 0x0400; 7406c3fb27SDimitry Andric uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000; 7506c3fb27SDimitry Andric uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000; 7606c3fb27SDimitry Andric uint32_t Imm10 = Hi & 0x03ff; 7706c3fb27SDimitry Andric uint32_t Imm11 = Lo & 0x07ff; 7806c3fb27SDimitry Andric return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1); 7906c3fb27SDimitry Andric } 8006c3fb27SDimitry Andric 8106c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and 8206c3fb27SDimitry Andric /// MOVW T3. 8306c3fb27SDimitry Andric /// 8406c3fb27SDimitry Andric /// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] 8506c3fb27SDimitry Andric /// 8606c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) { 8706c3fb27SDimitry Andric uint32_t Imm4 = (Value >> 12) & 0x0f; 8806c3fb27SDimitry Andric uint32_t Imm1 = (Value >> 11) & 0x01; 8906c3fb27SDimitry Andric uint32_t Imm3 = (Value >> 8) & 0x07; 9006c3fb27SDimitry Andric uint32_t Imm8 = Value & 0xff; 9106c3fb27SDimitry Andric return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8}; 9206c3fb27SDimitry Andric } 9306c3fb27SDimitry Andric 9406c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and 9506c3fb27SDimitry Andric /// MOVW T3. 9606c3fb27SDimitry Andric /// 9706c3fb27SDimitry Andric /// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8 9806c3fb27SDimitry Andric /// 9906c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 10006c3fb27SDimitry Andric uint32_t Imm4 = Hi & 0x0f; 10106c3fb27SDimitry Andric uint32_t Imm1 = (Hi >> 10) & 0x01; 10206c3fb27SDimitry Andric uint32_t Imm3 = (Lo >> 12) & 0x07; 10306c3fb27SDimitry Andric uint32_t Imm8 = Lo & 0xff; 10406c3fb27SDimitry Andric uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8; 10506c3fb27SDimitry Andric assert(Imm16 <= 0xffff && "Decoded value out-of-range"); 10606c3fb27SDimitry Andric return Imm16; 10706c3fb27SDimitry Andric } 10806c3fb27SDimitry Andric 10906c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3. 11006c3fb27SDimitry Andric /// 11106c3fb27SDimitry Andric /// Rd4 -> [0000000000000000, 0000:Rd4:00000000] 11206c3fb27SDimitry Andric /// 11306c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) { 11406c3fb27SDimitry Andric uint32_t Rd4 = (Value & 0x0f) << 8; 11506c3fb27SDimitry Andric return HalfWords{0, Rd4}; 11606c3fb27SDimitry Andric } 11706c3fb27SDimitry Andric 11806c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3. 11906c3fb27SDimitry Andric /// 12006c3fb27SDimitry Andric /// [0000000000000000, 0000:Rd4:00000000] -> Rd4 12106c3fb27SDimitry Andric /// 12206c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 12306c3fb27SDimitry Andric uint32_t Rd4 = (Lo >> 8) & 0x0f; 12406c3fb27SDimitry Andric return Rd4; 12506c3fb27SDimitry Andric } 12606c3fb27SDimitry Andric 12706c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords. 12806c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi), 12906c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo). 13006c3fb27SDimitry Andric struct WritableThumbRelocation { 13106c3fb27SDimitry Andric /// Create a writable reference to a Thumb32 fixup. 13206c3fb27SDimitry Andric WritableThumbRelocation(char *FixupPtr) 13306c3fb27SDimitry Andric : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)}, 13406c3fb27SDimitry Andric Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {} 13506c3fb27SDimitry Andric 13606c3fb27SDimitry Andric support::ulittle16_t &Hi; // First halfword 13706c3fb27SDimitry Andric support::ulittle16_t &Lo; // Second halfword 13806c3fb27SDimitry Andric }; 13906c3fb27SDimitry Andric 14006c3fb27SDimitry Andric struct ThumbRelocation { 14106c3fb27SDimitry Andric /// Create a read-only reference to a Thumb32 fixup. 14206c3fb27SDimitry Andric ThumbRelocation(const char *FixupPtr) 14306c3fb27SDimitry Andric : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)}, 14406c3fb27SDimitry Andric Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {} 14506c3fb27SDimitry Andric 14606c3fb27SDimitry Andric /// Create a read-only Thumb32 fixup from a writeable one. 14706c3fb27SDimitry Andric ThumbRelocation(WritableThumbRelocation &Writable) 14806c3fb27SDimitry Andric : Hi{Writable.Hi}, Lo(Writable.Lo) {} 14906c3fb27SDimitry Andric 15006c3fb27SDimitry Andric const support::ulittle16_t &Hi; // First halfword 15106c3fb27SDimitry Andric const support::ulittle16_t &Lo; // Second halfword 15206c3fb27SDimitry Andric }; 15306c3fb27SDimitry Andric 15406c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, 15506c3fb27SDimitry Andric Edge::Kind Kind) { 15606c3fb27SDimitry Andric return make_error<JITLinkError>( 15706c3fb27SDimitry Andric formatv("Invalid opcode [ 0x{0:x4}, 0x{1:x4} ] for relocation: {2}", 15806c3fb27SDimitry Andric static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo), 15906c3fb27SDimitry Andric G.getEdgeKindName(Kind))); 16006c3fb27SDimitry Andric } 16106c3fb27SDimitry Andric 16206c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> bool checkOpcode(const ThumbRelocation &R) { 16306c3fb27SDimitry Andric uint16_t Hi = R.Hi & FixupInfo<Kind>::OpcodeMask.Hi; 16406c3fb27SDimitry Andric uint16_t Lo = R.Lo & FixupInfo<Kind>::OpcodeMask.Lo; 16506c3fb27SDimitry Andric return Hi == FixupInfo<Kind>::Opcode.Hi && Lo == FixupInfo<Kind>::Opcode.Lo; 16606c3fb27SDimitry Andric } 16706c3fb27SDimitry Andric 16806c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 16906c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) { 17006c3fb27SDimitry Andric uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi; 17106c3fb27SDimitry Andric uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo; 17206c3fb27SDimitry Andric return Hi == Reg.Hi && Lo == Reg.Lo; 17306c3fb27SDimitry Andric } 17406c3fb27SDimitry Andric 17506c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 176*5c16e71dSDimitry Andric void writeRegister(WritableThumbRelocation &R, HalfWords Reg) { 17706c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask; 17806c3fb27SDimitry Andric assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Hi & Reg.Hi) == Reg.Hi && 17906c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 18006c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi; 18106c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo; 18206c3fb27SDimitry Andric } 18306c3fb27SDimitry Andric 18406c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 18506c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) { 18606c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask; 18706c3fb27SDimitry Andric assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Hi & Imm.Hi) == Imm.Hi && 18806c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 18906c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi; 19006c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo; 19106c3fb27SDimitry Andric } 19206c3fb27SDimitry Andric 19306c3fb27SDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E) { 19406c3fb27SDimitry Andric support::endianness Endian = G.getEndianness(); 19506c3fb27SDimitry Andric assert(Endian != support::native && "Declare as little or big explicitly"); 19606c3fb27SDimitry Andric 19706c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 19806c3fb27SDimitry Andric const char *BlockWorkingMem = B.getContent().data(); 19906c3fb27SDimitry Andric const char *FixupPtr = BlockWorkingMem + E.getOffset(); 20006c3fb27SDimitry Andric 20106c3fb27SDimitry Andric switch (Kind) { 20206c3fb27SDimitry Andric case Data_Delta32: 20306c3fb27SDimitry Andric case Data_Pointer32: 20406c3fb27SDimitry Andric return SignExtend64<32>(support::endian::read32(FixupPtr, Endian)); 20506c3fb27SDimitry Andric default: 20606c3fb27SDimitry Andric return make_error<JITLinkError>( 20706c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 20806c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 20906c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 21006c3fb27SDimitry Andric } 21106c3fb27SDimitry Andric } 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) { 21406c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 21506c3fb27SDimitry Andric 21606c3fb27SDimitry Andric switch (Kind) { 21706c3fb27SDimitry Andric case Arm_Call: 21806c3fb27SDimitry Andric return make_error<JITLinkError>( 21906c3fb27SDimitry Andric "Addend extraction for relocation type not yet implemented: " + 22006c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 22106c3fb27SDimitry Andric default: 22206c3fb27SDimitry Andric return make_error<JITLinkError>( 22306c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 22406c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 22506c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 22606c3fb27SDimitry Andric } 22706c3fb27SDimitry Andric } 22806c3fb27SDimitry Andric 22906c3fb27SDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E, 23006c3fb27SDimitry Andric const ArmConfig &ArmCfg) { 23106c3fb27SDimitry Andric ThumbRelocation R(B.getContent().data() + E.getOffset()); 23206c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 23306c3fb27SDimitry Andric 23406c3fb27SDimitry Andric switch (Kind) { 23506c3fb27SDimitry Andric case Thumb_Call: 23606c3fb27SDimitry Andric if (!checkOpcode<Thumb_Call>(R)) 23706c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 23806c3fb27SDimitry Andric return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 23906c3fb27SDimitry Andric ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 24006c3fb27SDimitry Andric : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 24106c3fb27SDimitry Andric 24206c3fb27SDimitry Andric case Thumb_Jump24: 24306c3fb27SDimitry Andric if (!checkOpcode<Thumb_Jump24>(R)) 24406c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 24506c3fb27SDimitry Andric if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional) 24606c3fb27SDimitry Andric return make_error<JITLinkError>("Relocation expects an unconditional " 24706c3fb27SDimitry Andric "B.W branch instruction: " + 24806c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 24906c3fb27SDimitry Andric return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 25006c3fb27SDimitry Andric ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 25106c3fb27SDimitry Andric : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 25206c3fb27SDimitry Andric 25306c3fb27SDimitry Andric case Thumb_MovwAbsNC: 25406c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovwAbsNC>(R)) 25506c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 25606c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 25706c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 25806c3fb27SDimitry Andric 25906c3fb27SDimitry Andric case Thumb_MovtAbs: 26006c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovtAbs>(R)) 26106c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 26206c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 26306c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 26406c3fb27SDimitry Andric 26506c3fb27SDimitry Andric default: 26606c3fb27SDimitry Andric return make_error<JITLinkError>( 26706c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 26806c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 26906c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 27006c3fb27SDimitry Andric } 27106c3fb27SDimitry Andric } 27206c3fb27SDimitry Andric 27306c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) { 27406c3fb27SDimitry Andric using namespace support; 27506c3fb27SDimitry Andric 27606c3fb27SDimitry Andric char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 27706c3fb27SDimitry Andric char *FixupPtr = BlockWorkingMem + E.getOffset(); 27806c3fb27SDimitry Andric 27906c3fb27SDimitry Andric auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) { 28006c3fb27SDimitry Andric assert(Endian != native && "Must be explicit: little or big"); 28106c3fb27SDimitry Andric assert(isInt<32>(Value) && "Must be in signed 32-bit range"); 28206c3fb27SDimitry Andric uint32_t Imm = static_cast<int32_t>(Value); 28306c3fb27SDimitry Andric if (LLVM_LIKELY(Endian == little)) 28406c3fb27SDimitry Andric endian::write32<little>(FixupPtr, Imm); 28506c3fb27SDimitry Andric else 28606c3fb27SDimitry Andric endian::write32<big>(FixupPtr, Imm); 28706c3fb27SDimitry Andric }; 28806c3fb27SDimitry Andric 28906c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 29006c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 29106c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 29206c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 29306c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 29406c3fb27SDimitry Andric assert(!TargetSymbol.hasTargetFlags(ThumbSymbol)); 29506c3fb27SDimitry Andric 29606c3fb27SDimitry Andric // Regular data relocations have size 4, alignment 1 and write the full 32-bit 29706c3fb27SDimitry Andric // result to the place; no need for overflow checking. There are three 29806c3fb27SDimitry Andric // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31 29906c3fb27SDimitry Andric switch (Kind) { 30006c3fb27SDimitry Andric case Data_Delta32: { 30106c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 30206c3fb27SDimitry Andric if (!isInt<32>(Value)) 30306c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 30406c3fb27SDimitry Andric Write32(Value); 30506c3fb27SDimitry Andric return Error::success(); 30606c3fb27SDimitry Andric } 30706c3fb27SDimitry Andric case Data_Pointer32: { 30806c3fb27SDimitry Andric int64_t Value = TargetAddress + Addend; 30906c3fb27SDimitry Andric if (!isInt<32>(Value)) 31006c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 31106c3fb27SDimitry Andric Write32(Value); 31206c3fb27SDimitry Andric return Error::success(); 31306c3fb27SDimitry Andric } 31406c3fb27SDimitry Andric default: 31506c3fb27SDimitry Andric return make_error<JITLinkError>( 31606c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 31706c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 31806c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 31906c3fb27SDimitry Andric } 32006c3fb27SDimitry Andric } 32106c3fb27SDimitry Andric 32206c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) { 32306c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 32406c3fb27SDimitry Andric 32506c3fb27SDimitry Andric switch (Kind) { 32606c3fb27SDimitry Andric case Arm_Call: 32706c3fb27SDimitry Andric return make_error<JITLinkError>( 32806c3fb27SDimitry Andric "Fix-up for relocation type not yet implemented: " + 32906c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 33006c3fb27SDimitry Andric default: 33106c3fb27SDimitry Andric return make_error<JITLinkError>( 33206c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 33306c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 33406c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 33506c3fb27SDimitry Andric } 33606c3fb27SDimitry Andric } 33706c3fb27SDimitry Andric 33806c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, 33906c3fb27SDimitry Andric const ArmConfig &ArmCfg) { 34006c3fb27SDimitry Andric WritableThumbRelocation R(B.getAlreadyMutableContent().data() + 34106c3fb27SDimitry Andric E.getOffset()); 34206c3fb27SDimitry Andric 34306c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 34406c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 34506c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 34606c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 34706c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 34806c3fb27SDimitry Andric if (TargetSymbol.hasTargetFlags(ThumbSymbol)) 34906c3fb27SDimitry Andric TargetAddress |= 0x01; 35006c3fb27SDimitry Andric 35106c3fb27SDimitry Andric switch (Kind) { 35206c3fb27SDimitry Andric case Thumb_Jump24: { 35306c3fb27SDimitry Andric if (!checkOpcode<Thumb_Jump24>(R)) 35406c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 35506c3fb27SDimitry Andric if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional) 35606c3fb27SDimitry Andric return make_error<JITLinkError>("Relocation expects an unconditional " 35706c3fb27SDimitry Andric "B.W branch instruction: " + 35806c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 35906c3fb27SDimitry Andric if (!(TargetSymbol.hasTargetFlags(ThumbSymbol))) 36006c3fb27SDimitry Andric return make_error<JITLinkError>("Branch relocation needs interworking " 36106c3fb27SDimitry Andric "stub when bridging to ARM: " + 36206c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 36306c3fb27SDimitry Andric 36406c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 36506c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 36606c3fb27SDimitry Andric if (!isInt<25>(Value)) 36706c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 36806c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 36906c3fb27SDimitry Andric } else { 37006c3fb27SDimitry Andric if (!isInt<22>(Value)) 37106c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 37206c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value)); 37306c3fb27SDimitry Andric } 37406c3fb27SDimitry Andric 37506c3fb27SDimitry Andric return Error::success(); 37606c3fb27SDimitry Andric } 37706c3fb27SDimitry Andric 37806c3fb27SDimitry Andric case Thumb_Call: { 37906c3fb27SDimitry Andric if (!checkOpcode<Thumb_Call>(R)) 38006c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 38106c3fb27SDimitry Andric 38206c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 38306c3fb27SDimitry Andric 38406c3fb27SDimitry Andric // The call instruction itself is Thumb. The call destination can either be 38506c3fb27SDimitry Andric // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm. 38606c3fb27SDimitry Andric bool TargetIsArm = !TargetSymbol.hasTargetFlags(ThumbSymbol); 38706c3fb27SDimitry Andric bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0; 38806c3fb27SDimitry Andric if (TargetIsArm != InstrIsBlx) { 38906c3fb27SDimitry Andric if (LLVM_LIKELY(TargetIsArm)) { 39006c3fb27SDimitry Andric // Change opcode BL -> BLX and fix range value (account for 4-byte 39106c3fb27SDimitry Andric // aligned destination while instruction may only be 2-byte aligned 39206c3fb27SDimitry Andric // and clear Thumb bit). 39306c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 39406c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH; 39506c3fb27SDimitry Andric Value = alignTo(Value, 4); 39606c3fb27SDimitry Andric } else { 39706c3fb27SDimitry Andric // Change opcode BLX -> BL and set Thumb bit 39806c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 39906c3fb27SDimitry Andric Value |= 0x01; 40006c3fb27SDimitry Andric } 40106c3fb27SDimitry Andric } 40206c3fb27SDimitry Andric 40306c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 40406c3fb27SDimitry Andric if (!isInt<25>(Value)) 40506c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 40606c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 40706c3fb27SDimitry Andric } else { 40806c3fb27SDimitry Andric if (!isInt<22>(Value)) 40906c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 41006c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value)); 41106c3fb27SDimitry Andric } 41206c3fb27SDimitry Andric 41306c3fb27SDimitry Andric assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) || 41406c3fb27SDimitry Andric (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) && 41506c3fb27SDimitry Andric "Opcode BLX implies H bit is clear (avoid UB in BLX T2)"); 41606c3fb27SDimitry Andric return Error::success(); 41706c3fb27SDimitry Andric } 41806c3fb27SDimitry Andric 41906c3fb27SDimitry Andric case Thumb_MovwAbsNC: { 42006c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovwAbsNC>(R)) 42106c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 42206c3fb27SDimitry Andric uint16_t Value = (TargetAddress + Addend) & 0xffff; 42306c3fb27SDimitry Andric writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value)); 42406c3fb27SDimitry Andric return Error::success(); 42506c3fb27SDimitry Andric } 42606c3fb27SDimitry Andric 42706c3fb27SDimitry Andric case Thumb_MovtAbs: { 42806c3fb27SDimitry Andric if (!checkOpcode<Thumb_MovtAbs>(R)) 42906c3fb27SDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 43006c3fb27SDimitry Andric uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 43106c3fb27SDimitry Andric writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value)); 43206c3fb27SDimitry Andric return Error::success(); 43306c3fb27SDimitry Andric } 43406c3fb27SDimitry Andric 43506c3fb27SDimitry Andric default: 43606c3fb27SDimitry Andric return make_error<JITLinkError>( 43706c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 43806c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 43906c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 44006c3fb27SDimitry Andric } 44106c3fb27SDimitry Andric } 44206c3fb27SDimitry Andric 44306c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = { 44406c3fb27SDimitry Andric 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit 44506c3fb27SDimitry Andric 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit 44606c3fb27SDimitry Andric 0x60, 0x47 // bx r12 44706c3fb27SDimitry Andric }; 44806c3fb27SDimitry Andric 44906c3fb27SDimitry Andric template <> 45006c3fb27SDimitry Andric Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) { 45106c3fb27SDimitry Andric constexpr uint64_t Alignment = 4; 45206c3fb27SDimitry Andric Block &B = addStub(G, Thumbv7ABS, Alignment); 45306c3fb27SDimitry Andric LLVM_DEBUG({ 45406c3fb27SDimitry Andric const char *StubPtr = B.getContent().data(); 45506c3fb27SDimitry Andric HalfWords Reg12 = encodeRegMovtT1MovwT3(12); 45606c3fb27SDimitry Andric assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && 45706c3fb27SDimitry Andric checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && 45806c3fb27SDimitry Andric "Linker generated stubs may only corrupt register r12 (IP)"); 45906c3fb27SDimitry Andric }); 46006c3fb27SDimitry Andric B.addEdge(Thumb_MovwAbsNC, 0, Target, 0); 46106c3fb27SDimitry Andric B.addEdge(Thumb_MovtAbs, 4, Target, 0); 46206c3fb27SDimitry Andric Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false); 46306c3fb27SDimitry Andric Stub.setTargetFlags(ThumbSymbol); 46406c3fb27SDimitry Andric return Stub; 46506c3fb27SDimitry Andric } 46606c3fb27SDimitry Andric 46706c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) { 46806c3fb27SDimitry Andric #define KIND_NAME_CASE(K) \ 46906c3fb27SDimitry Andric case K: \ 47006c3fb27SDimitry Andric return #K; 47106c3fb27SDimitry Andric 47206c3fb27SDimitry Andric switch (K) { 47306c3fb27SDimitry Andric KIND_NAME_CASE(Data_Delta32) 47406c3fb27SDimitry Andric KIND_NAME_CASE(Arm_Call) 47506c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Call) 47606c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Jump24) 47706c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovwAbsNC) 47806c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovtAbs) 47906c3fb27SDimitry Andric default: 48006c3fb27SDimitry Andric return getGenericEdgeKindName(K); 48106c3fb27SDimitry Andric } 48206c3fb27SDimitry Andric #undef KIND_NAME_CASE 48306c3fb27SDimitry Andric } 48406c3fb27SDimitry Andric 48506c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) { 48606c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K) \ 48706c3fb27SDimitry Andric case K: \ 48806c3fb27SDimitry Andric return #K; 48906c3fb27SDimitry Andric 49006c3fb27SDimitry Andric using namespace ARMBuildAttrs; 49106c3fb27SDimitry Andric switch (K) { 49206c3fb27SDimitry Andric CPUARCH_NAME_CASE(Pre_v4) 49306c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4) 49406c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4T) 49506c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5T) 49606c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TE) 49706c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TEJ) 49806c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6) 49906c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6KZ) 50006c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6T2) 50106c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6K) 50206c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7) 50306c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6_M) 50406c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6S_M) 50506c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7E_M) 50606c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_A) 50706c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_R) 50806c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Base) 50906c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Main) 51006c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_1_M_Main) 51106c3fb27SDimitry Andric CPUARCH_NAME_CASE(v9_A) 51206c3fb27SDimitry Andric } 51306c3fb27SDimitry Andric llvm_unreachable("Missing CPUArch in switch?"); 51406c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE 51506c3fb27SDimitry Andric } 51606c3fb27SDimitry Andric 51706c3fb27SDimitry Andric } // namespace aarch32 51806c3fb27SDimitry Andric } // namespace jitlink 51906c3fb27SDimitry Andric } // namespace llvm 520