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" 20*5f757f3fSDimitry Andric #include "llvm/Support/ManagedStatic.h" 2106c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h" 2206c3fb27SDimitry Andric 2306c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink" 2406c3fb27SDimitry Andric 2506c3fb27SDimitry Andric namespace llvm { 2606c3fb27SDimitry Andric namespace jitlink { 2706c3fb27SDimitry Andric namespace aarch32 { 2806c3fb27SDimitry Andric 29*5f757f3fSDimitry Andric /// Check whether the given target flags are set for this Symbol. 30*5f757f3fSDimitry Andric bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags) { 31*5f757f3fSDimitry Andric return static_cast<TargetFlagsType>(Sym.getTargetFlags()) & Flags; 32*5f757f3fSDimitry Andric } 33*5f757f3fSDimitry Andric 3406c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range 3506c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 3606c3fb27SDimitry Andric /// 3706c3fb27SDimitry Andric /// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ] 3806c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 3906c3fb27SDimitry Andric /// 4006c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) { 4106c3fb27SDimitry Andric constexpr uint32_t J1J2 = 0x2800; 4206c3fb27SDimitry Andric uint32_t Imm11H = (Value >> 12) & 0x07ff; 4306c3fb27SDimitry Andric uint32_t Imm11L = (Value >> 1) & 0x07ff; 4406c3fb27SDimitry Andric return HalfWords{Imm11H, Imm11L | J1J2}; 4506c3fb27SDimitry Andric } 4606c3fb27SDimitry Andric 4706c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range 4806c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 4906c3fb27SDimitry Andric /// 5006c3fb27SDimitry Andric /// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0 5106c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 5206c3fb27SDimitry Andric /// 5306c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) { 5406c3fb27SDimitry Andric uint32_t Imm11H = Hi & 0x07ff; 5506c3fb27SDimitry Andric uint32_t Imm11L = Lo & 0x07ff; 5606c3fb27SDimitry Andric return SignExtend64<22>(Imm11H << 12 | Imm11L << 1); 5706c3fb27SDimitry Andric } 5806c3fb27SDimitry Andric 5906c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range 6006c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 6106c3fb27SDimitry Andric /// 6206c3fb27SDimitry Andric /// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ] 6306c3fb27SDimitry Andric /// 6406c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) { 6506c3fb27SDimitry Andric uint32_t S = (Value >> 14) & 0x0400; 6606c3fb27SDimitry Andric uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000); 6706c3fb27SDimitry Andric uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800); 6806c3fb27SDimitry Andric uint32_t Imm10 = (Value >> 12) & 0x03ff; 6906c3fb27SDimitry Andric uint32_t Imm11 = (Value >> 1) & 0x07ff; 7006c3fb27SDimitry Andric return HalfWords{S | Imm10, J1 | J2 | Imm11}; 7106c3fb27SDimitry Andric } 7206c3fb27SDimitry Andric 7306c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range 7406c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 7506c3fb27SDimitry Andric /// 7606c3fb27SDimitry Andric /// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0 7706c3fb27SDimitry Andric /// 7806c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) { 7906c3fb27SDimitry Andric uint32_t S = Hi & 0x0400; 8006c3fb27SDimitry Andric uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000; 8106c3fb27SDimitry Andric uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000; 8206c3fb27SDimitry Andric uint32_t Imm10 = Hi & 0x03ff; 8306c3fb27SDimitry Andric uint32_t Imm11 = Lo & 0x07ff; 8406c3fb27SDimitry Andric return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1); 8506c3fb27SDimitry Andric } 8606c3fb27SDimitry Andric 87*5f757f3fSDimitry Andric /// Encode 26-bit immediate value for branch instructions 88*5f757f3fSDimitry Andric /// (formats B A1, BL A1 and BLX A2). 89*5f757f3fSDimitry Andric /// 90*5f757f3fSDimitry Andric /// Imm24:00 -> 00000000:Imm24 91*5f757f3fSDimitry Andric /// 92*5f757f3fSDimitry Andric uint32_t encodeImmBA1BlA1BlxA2(int64_t Value) { 93*5f757f3fSDimitry Andric return (Value >> 2) & 0x00ffffff; 94*5f757f3fSDimitry Andric } 95*5f757f3fSDimitry Andric 96*5f757f3fSDimitry Andric /// Decode 26-bit immediate value for branch instructions 97*5f757f3fSDimitry Andric /// (formats B A1, BL A1 and BLX A2). 98*5f757f3fSDimitry Andric /// 99*5f757f3fSDimitry Andric /// 00000000:Imm24 -> Imm24:00 100*5f757f3fSDimitry Andric /// 101*5f757f3fSDimitry Andric int64_t decodeImmBA1BlA1BlxA2(int64_t Value) { 102*5f757f3fSDimitry Andric return SignExtend64<26>((Value & 0x00ffffff) << 2); 103*5f757f3fSDimitry Andric } 104*5f757f3fSDimitry Andric 10506c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and 10606c3fb27SDimitry Andric /// MOVW T3. 10706c3fb27SDimitry Andric /// 10806c3fb27SDimitry Andric /// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] 10906c3fb27SDimitry Andric /// 11006c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) { 11106c3fb27SDimitry Andric uint32_t Imm4 = (Value >> 12) & 0x0f; 11206c3fb27SDimitry Andric uint32_t Imm1 = (Value >> 11) & 0x01; 11306c3fb27SDimitry Andric uint32_t Imm3 = (Value >> 8) & 0x07; 11406c3fb27SDimitry Andric uint32_t Imm8 = Value & 0xff; 11506c3fb27SDimitry Andric return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8}; 11606c3fb27SDimitry Andric } 11706c3fb27SDimitry Andric 11806c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and 11906c3fb27SDimitry Andric /// MOVW T3. 12006c3fb27SDimitry Andric /// 12106c3fb27SDimitry Andric /// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8 12206c3fb27SDimitry Andric /// 12306c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 12406c3fb27SDimitry Andric uint32_t Imm4 = Hi & 0x0f; 12506c3fb27SDimitry Andric uint32_t Imm1 = (Hi >> 10) & 0x01; 12606c3fb27SDimitry Andric uint32_t Imm3 = (Lo >> 12) & 0x07; 12706c3fb27SDimitry Andric uint32_t Imm8 = Lo & 0xff; 12806c3fb27SDimitry Andric uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8; 12906c3fb27SDimitry Andric assert(Imm16 <= 0xffff && "Decoded value out-of-range"); 13006c3fb27SDimitry Andric return Imm16; 13106c3fb27SDimitry Andric } 13206c3fb27SDimitry Andric 13306c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3. 13406c3fb27SDimitry Andric /// 13506c3fb27SDimitry Andric /// Rd4 -> [0000000000000000, 0000:Rd4:00000000] 13606c3fb27SDimitry Andric /// 13706c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) { 13806c3fb27SDimitry Andric uint32_t Rd4 = (Value & 0x0f) << 8; 13906c3fb27SDimitry Andric return HalfWords{0, Rd4}; 14006c3fb27SDimitry Andric } 14106c3fb27SDimitry Andric 14206c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3. 14306c3fb27SDimitry Andric /// 14406c3fb27SDimitry Andric /// [0000000000000000, 0000:Rd4:00000000] -> Rd4 14506c3fb27SDimitry Andric /// 14606c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 14706c3fb27SDimitry Andric uint32_t Rd4 = (Lo >> 8) & 0x0f; 14806c3fb27SDimitry Andric return Rd4; 14906c3fb27SDimitry Andric } 15006c3fb27SDimitry Andric 151*5f757f3fSDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT A1 and 152*5f757f3fSDimitry Andric /// MOVW A2. 153*5f757f3fSDimitry Andric /// 154*5f757f3fSDimitry Andric /// Imm4:Imm12 -> 000000000000:Imm4:0000:Imm12 155*5f757f3fSDimitry Andric /// 156*5f757f3fSDimitry Andric uint32_t encodeImmMovtA1MovwA2(uint16_t Value) { 157*5f757f3fSDimitry Andric uint32_t Imm4 = (Value >> 12) & 0x0f; 158*5f757f3fSDimitry Andric uint32_t Imm12 = Value & 0x0fff; 159*5f757f3fSDimitry Andric return (Imm4 << 16) | Imm12; 160*5f757f3fSDimitry Andric } 161*5f757f3fSDimitry Andric 162*5f757f3fSDimitry Andric /// Decode 16-bit immediate value for move instruction formats MOVT A1 and 163*5f757f3fSDimitry Andric /// MOVW A2. 164*5f757f3fSDimitry Andric /// 165*5f757f3fSDimitry Andric /// 000000000000:Imm4:0000:Imm12 -> Imm4:Imm12 166*5f757f3fSDimitry Andric /// 167*5f757f3fSDimitry Andric uint16_t decodeImmMovtA1MovwA2(uint64_t Value) { 168*5f757f3fSDimitry Andric uint32_t Imm4 = (Value >> 16) & 0x0f; 169*5f757f3fSDimitry Andric uint32_t Imm12 = Value & 0x0fff; 170*5f757f3fSDimitry Andric return (Imm4 << 12) | Imm12; 171*5f757f3fSDimitry Andric } 172*5f757f3fSDimitry Andric 173*5f757f3fSDimitry Andric /// Encode register ID for instruction formats MOVT A1 and 174*5f757f3fSDimitry Andric /// MOVW A2. 175*5f757f3fSDimitry Andric /// 176*5f757f3fSDimitry Andric /// Rd4 -> 0000000000000000:Rd4:000000000000 177*5f757f3fSDimitry Andric /// 178*5f757f3fSDimitry Andric uint32_t encodeRegMovtA1MovwA2(int64_t Value) { 179*5f757f3fSDimitry Andric uint32_t Rd4 = (Value & 0x00000f) << 12; 180*5f757f3fSDimitry Andric return Rd4; 181*5f757f3fSDimitry Andric } 182*5f757f3fSDimitry Andric 183*5f757f3fSDimitry Andric /// Decode register ID for instruction formats MOVT A1 and 184*5f757f3fSDimitry Andric /// MOVW A2. 185*5f757f3fSDimitry Andric /// 186*5f757f3fSDimitry Andric /// 0000000000000000:Rd4:000000000000 -> Rd4 187*5f757f3fSDimitry Andric /// 188*5f757f3fSDimitry Andric int64_t decodeRegMovtA1MovwA2(uint64_t Value) { 189*5f757f3fSDimitry Andric uint32_t Rd4 = (Value >> 12) & 0x00000f; 190*5f757f3fSDimitry Andric return Rd4; 191*5f757f3fSDimitry Andric } 192*5f757f3fSDimitry Andric 193*5f757f3fSDimitry Andric namespace { 194*5f757f3fSDimitry Andric 19506c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords. 19606c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi), 19706c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo). 19806c3fb27SDimitry Andric struct WritableThumbRelocation { 19906c3fb27SDimitry Andric /// Create a writable reference to a Thumb32 fixup. 20006c3fb27SDimitry Andric WritableThumbRelocation(char *FixupPtr) 20106c3fb27SDimitry Andric : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)}, 20206c3fb27SDimitry Andric Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {} 20306c3fb27SDimitry Andric 20406c3fb27SDimitry Andric support::ulittle16_t &Hi; // First halfword 20506c3fb27SDimitry Andric support::ulittle16_t &Lo; // Second halfword 20606c3fb27SDimitry Andric }; 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric struct ThumbRelocation { 20906c3fb27SDimitry Andric /// Create a read-only reference to a Thumb32 fixup. 21006c3fb27SDimitry Andric ThumbRelocation(const char *FixupPtr) 21106c3fb27SDimitry Andric : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)}, 21206c3fb27SDimitry Andric Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {} 21306c3fb27SDimitry Andric 21406c3fb27SDimitry Andric /// Create a read-only Thumb32 fixup from a writeable one. 21506c3fb27SDimitry Andric ThumbRelocation(WritableThumbRelocation &Writable) 21606c3fb27SDimitry Andric : Hi{Writable.Hi}, Lo(Writable.Lo) {} 21706c3fb27SDimitry Andric 21806c3fb27SDimitry Andric const support::ulittle16_t &Hi; // First halfword 21906c3fb27SDimitry Andric const support::ulittle16_t &Lo; // Second halfword 22006c3fb27SDimitry Andric }; 22106c3fb27SDimitry Andric 222*5f757f3fSDimitry Andric struct WritableArmRelocation { 223*5f757f3fSDimitry Andric WritableArmRelocation(char *FixupPtr) 224*5f757f3fSDimitry Andric : Wd{*reinterpret_cast<support::ulittle32_t *>(FixupPtr)} {} 225*5f757f3fSDimitry Andric 226*5f757f3fSDimitry Andric support::ulittle32_t &Wd; 227*5f757f3fSDimitry Andric }; 228*5f757f3fSDimitry Andric 229*5f757f3fSDimitry Andric struct ArmRelocation { 230*5f757f3fSDimitry Andric ArmRelocation(const char *FixupPtr) 231*5f757f3fSDimitry Andric : Wd{*reinterpret_cast<const support::ulittle32_t *>(FixupPtr)} {} 232*5f757f3fSDimitry Andric 233*5f757f3fSDimitry Andric ArmRelocation(WritableArmRelocation &Writable) : Wd{Writable.Wd} {} 234*5f757f3fSDimitry Andric 235*5f757f3fSDimitry Andric const support::ulittle32_t &Wd; 236*5f757f3fSDimitry Andric }; 237*5f757f3fSDimitry Andric 23806c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, 23906c3fb27SDimitry Andric Edge::Kind Kind) { 24006c3fb27SDimitry Andric return make_error<JITLinkError>( 241*5f757f3fSDimitry Andric formatv("Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}", 24206c3fb27SDimitry Andric static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo), 24306c3fb27SDimitry Andric G.getEdgeKindName(Kind))); 24406c3fb27SDimitry Andric } 24506c3fb27SDimitry Andric 246*5f757f3fSDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ArmRelocation &R, 247*5f757f3fSDimitry Andric Edge::Kind Kind) { 248*5f757f3fSDimitry Andric return make_error<JITLinkError>( 249*5f757f3fSDimitry Andric formatv("Invalid opcode {0:x8} for relocation: {1}", 250*5f757f3fSDimitry Andric static_cast<uint32_t>(R.Wd), G.getEdgeKindName(Kind))); 251*5f757f3fSDimitry Andric } 252*5f757f3fSDimitry Andric 253*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> constexpr bool isArm() { 254*5f757f3fSDimitry Andric return FirstArmRelocation <= K && K <= LastArmRelocation; 255*5f757f3fSDimitry Andric } 256*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> constexpr bool isThumb() { 257*5f757f3fSDimitry Andric return FirstThumbRelocation <= K && K <= LastThumbRelocation; 258*5f757f3fSDimitry Andric } 259*5f757f3fSDimitry Andric 260*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> static bool checkOpcodeArm(uint32_t Wd) { 261*5f757f3fSDimitry Andric return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode; 262*5f757f3fSDimitry Andric } 263*5f757f3fSDimitry Andric 264*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> 265*5f757f3fSDimitry Andric static bool checkOpcodeThumb(uint16_t Hi, uint16_t Lo) { 266*5f757f3fSDimitry Andric return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi && 267*5f757f3fSDimitry Andric (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo; 268*5f757f3fSDimitry Andric } 269*5f757f3fSDimitry Andric 270*5f757f3fSDimitry Andric class FixupInfoTable { 271*5f757f3fSDimitry Andric static constexpr size_t Items = LastRelocation + 1; 272*5f757f3fSDimitry Andric 273*5f757f3fSDimitry Andric public: 274*5f757f3fSDimitry Andric FixupInfoTable() { 275*5f757f3fSDimitry Andric populateEntries<FirstArmRelocation, LastArmRelocation>(); 276*5f757f3fSDimitry Andric populateEntries<FirstThumbRelocation, LastThumbRelocation>(); 277*5f757f3fSDimitry Andric } 278*5f757f3fSDimitry Andric 279*5f757f3fSDimitry Andric const FixupInfoBase *getEntry(Edge::Kind K) { 280*5f757f3fSDimitry Andric assert(K < Data.size() && "Index out of bounds"); 281*5f757f3fSDimitry Andric return Data.at(K).get(); 282*5f757f3fSDimitry Andric } 283*5f757f3fSDimitry Andric 284*5f757f3fSDimitry Andric private: 285*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK> void populateEntries() { 286*5f757f3fSDimitry Andric assert(K < Data.size() && "Index out of range"); 287*5f757f3fSDimitry Andric assert(Data.at(K) == nullptr && "Initialized entries are immutable"); 288*5f757f3fSDimitry Andric Data[K] = initEntry<K>(); 289*5f757f3fSDimitry Andric if constexpr (K < LastK) { 290*5f757f3fSDimitry Andric constexpr auto Next = static_cast<EdgeKind_aarch32>(K + 1); 291*5f757f3fSDimitry Andric populateEntries<Next, LastK>(); 292*5f757f3fSDimitry Andric } 293*5f757f3fSDimitry Andric } 294*5f757f3fSDimitry Andric 295*5f757f3fSDimitry Andric template <EdgeKind_aarch32 K> 296*5f757f3fSDimitry Andric static std::unique_ptr<FixupInfoBase> initEntry() { 297*5f757f3fSDimitry Andric auto Entry = std::make_unique<FixupInfo<K>>(); 298*5f757f3fSDimitry Andric static_assert(isArm<K>() != isThumb<K>(), "Classes are mutually exclusive"); 299*5f757f3fSDimitry Andric if constexpr (isArm<K>()) 300*5f757f3fSDimitry Andric Entry->checkOpcode = checkOpcodeArm<K>; 301*5f757f3fSDimitry Andric if constexpr (isThumb<K>()) 302*5f757f3fSDimitry Andric Entry->checkOpcode = checkOpcodeThumb<K>; 303*5f757f3fSDimitry Andric return Entry; 304*5f757f3fSDimitry Andric } 305*5f757f3fSDimitry Andric 306*5f757f3fSDimitry Andric private: 307*5f757f3fSDimitry Andric std::array<std::unique_ptr<FixupInfoBase>, Items> Data; 308*5f757f3fSDimitry Andric }; 309*5f757f3fSDimitry Andric 310*5f757f3fSDimitry Andric ManagedStatic<FixupInfoTable> DynFixupInfos; 311*5f757f3fSDimitry Andric 312*5f757f3fSDimitry Andric } // namespace 313*5f757f3fSDimitry Andric 314*5f757f3fSDimitry Andric static Error checkOpcode(LinkGraph &G, const ArmRelocation &R, 315*5f757f3fSDimitry Andric Edge::Kind Kind) { 316*5f757f3fSDimitry Andric assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation && 317*5f757f3fSDimitry Andric "Edge kind must be Arm relocation"); 318*5f757f3fSDimitry Andric const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind); 319*5f757f3fSDimitry Andric const FixupInfoArm &Info = *static_cast<const FixupInfoArm *>(Entry); 320*5f757f3fSDimitry Andric assert(Info.checkOpcode && "Opcode check is mandatory for Arm edges"); 321*5f757f3fSDimitry Andric if (!Info.checkOpcode(R.Wd)) 322*5f757f3fSDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 323*5f757f3fSDimitry Andric 324*5f757f3fSDimitry Andric return Error::success(); 325*5f757f3fSDimitry Andric } 326*5f757f3fSDimitry Andric 327*5f757f3fSDimitry Andric static Error checkOpcode(LinkGraph &G, const ThumbRelocation &R, 328*5f757f3fSDimitry Andric Edge::Kind Kind) { 329*5f757f3fSDimitry Andric assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation && 330*5f757f3fSDimitry Andric "Edge kind must be Thumb relocation"); 331*5f757f3fSDimitry Andric const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind); 332*5f757f3fSDimitry Andric const FixupInfoThumb &Info = *static_cast<const FixupInfoThumb *>(Entry); 333*5f757f3fSDimitry Andric assert(Info.checkOpcode && "Opcode check is mandatory for Thumb edges"); 334*5f757f3fSDimitry Andric if (!Info.checkOpcode(R.Hi, R.Lo)) 335*5f757f3fSDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 336*5f757f3fSDimitry Andric 337*5f757f3fSDimitry Andric return Error::success(); 338*5f757f3fSDimitry Andric } 339*5f757f3fSDimitry Andric 340*5f757f3fSDimitry Andric const FixupInfoBase *FixupInfoBase::getDynFixupInfo(Edge::Kind K) { 341*5f757f3fSDimitry Andric return DynFixupInfos->getEntry(K); 34206c3fb27SDimitry Andric } 34306c3fb27SDimitry Andric 34406c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 34506c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) { 34606c3fb27SDimitry Andric uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi; 34706c3fb27SDimitry Andric uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo; 34806c3fb27SDimitry Andric return Hi == Reg.Hi && Lo == Reg.Lo; 34906c3fb27SDimitry Andric } 35006c3fb27SDimitry Andric 35106c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 352*5f757f3fSDimitry Andric bool checkRegister(const ArmRelocation &R, uint32_t Reg) { 353*5f757f3fSDimitry Andric uint32_t Wd = R.Wd & FixupInfo<Kind>::RegMask; 354*5f757f3fSDimitry Andric return Wd == Reg; 355*5f757f3fSDimitry Andric } 356*5f757f3fSDimitry Andric 357*5f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind> 3585c16e71dSDimitry Andric void writeRegister(WritableThumbRelocation &R, HalfWords Reg) { 35906c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask; 360*5f757f3fSDimitry Andric assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Lo & Reg.Lo) == Reg.Lo && 36106c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 36206c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi; 36306c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo; 36406c3fb27SDimitry Andric } 36506c3fb27SDimitry Andric 36606c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 367*5f757f3fSDimitry Andric void writeRegister(WritableArmRelocation &R, uint32_t Reg) { 368*5f757f3fSDimitry Andric static constexpr uint32_t Mask = FixupInfo<Kind>::RegMask; 369*5f757f3fSDimitry Andric assert((Mask & Reg) == Reg && "Value bits exceed bit range of given mask"); 370*5f757f3fSDimitry Andric R.Wd = (R.Wd & ~Mask) | Reg; 371*5f757f3fSDimitry Andric } 372*5f757f3fSDimitry Andric 373*5f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind> 37406c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) { 37506c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask; 376*5f757f3fSDimitry Andric assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo && 37706c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 37806c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi; 37906c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo; 38006c3fb27SDimitry Andric } 38106c3fb27SDimitry Andric 382*5f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind> 383*5f757f3fSDimitry Andric void writeImmediate(WritableArmRelocation &R, uint32_t Imm) { 384*5f757f3fSDimitry Andric static constexpr uint32_t Mask = FixupInfo<Kind>::ImmMask; 385*5f757f3fSDimitry Andric assert((Mask & Imm) == Imm && "Value bits exceed bit range of given mask"); 386*5f757f3fSDimitry Andric R.Wd = (R.Wd & ~Mask) | Imm; 387*5f757f3fSDimitry Andric } 38806c3fb27SDimitry Andric 389*5f757f3fSDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset, 390*5f757f3fSDimitry Andric Edge::Kind Kind) { 391*5f757f3fSDimitry Andric endianness Endian = G.getEndianness(); 39206c3fb27SDimitry Andric const char *BlockWorkingMem = B.getContent().data(); 393*5f757f3fSDimitry Andric const char *FixupPtr = BlockWorkingMem + Offset; 39406c3fb27SDimitry Andric 39506c3fb27SDimitry Andric switch (Kind) { 39606c3fb27SDimitry Andric case Data_Delta32: 39706c3fb27SDimitry Andric case Data_Pointer32: 39806c3fb27SDimitry Andric return SignExtend64<32>(support::endian::read32(FixupPtr, Endian)); 39906c3fb27SDimitry Andric default: 40006c3fb27SDimitry Andric return make_error<JITLinkError>( 40106c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 40206c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 403*5f757f3fSDimitry Andric G.getEdgeKindName(Kind)); 40406c3fb27SDimitry Andric } 40506c3fb27SDimitry Andric } 40606c3fb27SDimitry Andric 407*5f757f3fSDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset, 408*5f757f3fSDimitry Andric Edge::Kind Kind) { 409*5f757f3fSDimitry Andric ArmRelocation R(B.getContent().data() + Offset); 410*5f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 411*5f757f3fSDimitry Andric return std::move(Err); 41206c3fb27SDimitry Andric 41306c3fb27SDimitry Andric switch (Kind) { 41406c3fb27SDimitry Andric case Arm_Call: 415*5f757f3fSDimitry Andric case Arm_Jump24: 416*5f757f3fSDimitry Andric return decodeImmBA1BlA1BlxA2(R.Wd); 417*5f757f3fSDimitry Andric 418*5f757f3fSDimitry Andric case Arm_MovtAbs: 419*5f757f3fSDimitry Andric case Arm_MovwAbsNC: 420*5f757f3fSDimitry Andric return decodeImmMovtA1MovwA2(R.Wd); 421*5f757f3fSDimitry Andric 42206c3fb27SDimitry Andric default: 42306c3fb27SDimitry Andric return make_error<JITLinkError>( 42406c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 42506c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 426*5f757f3fSDimitry Andric G.getEdgeKindName(Kind)); 42706c3fb27SDimitry Andric } 42806c3fb27SDimitry Andric } 42906c3fb27SDimitry Andric 430*5f757f3fSDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset, 431*5f757f3fSDimitry Andric Edge::Kind Kind, const ArmConfig &ArmCfg) { 432*5f757f3fSDimitry Andric ThumbRelocation R(B.getContent().data() + Offset); 433*5f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 434*5f757f3fSDimitry Andric return std::move(Err); 43506c3fb27SDimitry Andric 43606c3fb27SDimitry Andric switch (Kind) { 43706c3fb27SDimitry Andric case Thumb_Call: 43806c3fb27SDimitry Andric case Thumb_Jump24: 43906c3fb27SDimitry Andric return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 44006c3fb27SDimitry Andric ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 44106c3fb27SDimitry Andric : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 44206c3fb27SDimitry Andric 44306c3fb27SDimitry Andric case Thumb_MovwAbsNC: 444*5f757f3fSDimitry Andric case Thumb_MovwPrelNC: 44506c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 44606c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 44706c3fb27SDimitry Andric 44806c3fb27SDimitry Andric case Thumb_MovtAbs: 449*5f757f3fSDimitry Andric case Thumb_MovtPrel: 45006c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 45106c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 45206c3fb27SDimitry Andric 45306c3fb27SDimitry Andric default: 45406c3fb27SDimitry Andric return make_error<JITLinkError>( 45506c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 45606c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 457*5f757f3fSDimitry Andric G.getEdgeKindName(Kind)); 45806c3fb27SDimitry Andric } 45906c3fb27SDimitry Andric } 46006c3fb27SDimitry Andric 46106c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) { 46206c3fb27SDimitry Andric using namespace support; 46306c3fb27SDimitry Andric 46406c3fb27SDimitry Andric char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 46506c3fb27SDimitry Andric char *FixupPtr = BlockWorkingMem + E.getOffset(); 46606c3fb27SDimitry Andric 46706c3fb27SDimitry Andric auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) { 46806c3fb27SDimitry Andric assert(isInt<32>(Value) && "Must be in signed 32-bit range"); 46906c3fb27SDimitry Andric uint32_t Imm = static_cast<int32_t>(Value); 470*5f757f3fSDimitry Andric if (LLVM_LIKELY(Endian == endianness::little)) 471*5f757f3fSDimitry Andric endian::write32<endianness::little>(FixupPtr, Imm); 47206c3fb27SDimitry Andric else 473*5f757f3fSDimitry Andric endian::write32<endianness::big>(FixupPtr, Imm); 47406c3fb27SDimitry Andric }; 47506c3fb27SDimitry Andric 47606c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 47706c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 47806c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 47906c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 48006c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 48106c3fb27SDimitry Andric 48206c3fb27SDimitry Andric // Regular data relocations have size 4, alignment 1 and write the full 32-bit 48306c3fb27SDimitry Andric // result to the place; no need for overflow checking. There are three 48406c3fb27SDimitry Andric // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31 48506c3fb27SDimitry Andric switch (Kind) { 48606c3fb27SDimitry Andric case Data_Delta32: { 48706c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 48806c3fb27SDimitry Andric if (!isInt<32>(Value)) 48906c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 49006c3fb27SDimitry Andric Write32(Value); 49106c3fb27SDimitry Andric return Error::success(); 49206c3fb27SDimitry Andric } 49306c3fb27SDimitry Andric case Data_Pointer32: { 49406c3fb27SDimitry Andric int64_t Value = TargetAddress + Addend; 49506c3fb27SDimitry Andric if (!isInt<32>(Value)) 49606c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 49706c3fb27SDimitry Andric Write32(Value); 49806c3fb27SDimitry Andric return Error::success(); 49906c3fb27SDimitry Andric } 50006c3fb27SDimitry Andric default: 50106c3fb27SDimitry Andric return make_error<JITLinkError>( 50206c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 50306c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 50406c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 50506c3fb27SDimitry Andric } 50606c3fb27SDimitry Andric } 50706c3fb27SDimitry Andric 50806c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) { 509*5f757f3fSDimitry Andric WritableArmRelocation R(B.getAlreadyMutableContent().data() + E.getOffset()); 51006c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 511*5f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 512*5f757f3fSDimitry Andric return Err; 513*5f757f3fSDimitry Andric 514*5f757f3fSDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 515*5f757f3fSDimitry Andric int64_t Addend = E.getAddend(); 516*5f757f3fSDimitry Andric Symbol &TargetSymbol = E.getTarget(); 517*5f757f3fSDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 51806c3fb27SDimitry Andric 51906c3fb27SDimitry Andric switch (Kind) { 520*5f757f3fSDimitry Andric case Arm_Jump24: { 521*5f757f3fSDimitry Andric if (hasTargetFlags(TargetSymbol, ThumbSymbol)) 522*5f757f3fSDimitry Andric return make_error<JITLinkError>("Branch relocation needs interworking " 523*5f757f3fSDimitry Andric "stub when bridging to Thumb: " + 52406c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 525*5f757f3fSDimitry Andric 526*5f757f3fSDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 527*5f757f3fSDimitry Andric 528*5f757f3fSDimitry Andric if (!isInt<26>(Value)) 529*5f757f3fSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 530*5f757f3fSDimitry Andric writeImmediate<Arm_Jump24>(R, encodeImmBA1BlA1BlxA2(Value)); 531*5f757f3fSDimitry Andric 532*5f757f3fSDimitry Andric return Error::success(); 533*5f757f3fSDimitry Andric } 534*5f757f3fSDimitry Andric case Arm_Call: { 535*5f757f3fSDimitry Andric if ((R.Wd & FixupInfo<Arm_Call>::CondMask) != 536*5f757f3fSDimitry Andric FixupInfo<Arm_Call>::Unconditional) 537*5f757f3fSDimitry Andric return make_error<JITLinkError>("Relocation expects an unconditional " 538*5f757f3fSDimitry Andric "BL/BLX branch instruction: " + 539*5f757f3fSDimitry Andric StringRef(G.getEdgeKindName(Kind))); 540*5f757f3fSDimitry Andric 541*5f757f3fSDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 542*5f757f3fSDimitry Andric 543*5f757f3fSDimitry Andric // The call instruction itself is Arm. The call destination can either be 544*5f757f3fSDimitry Andric // Thumb or Arm. We use BL to stay in Arm and BLX to change to Thumb. 545*5f757f3fSDimitry Andric bool TargetIsThumb = hasTargetFlags(TargetSymbol, ThumbSymbol); 546*5f757f3fSDimitry Andric bool InstrIsBlx = (~R.Wd & FixupInfo<Arm_Call>::BitBlx) == 0; 547*5f757f3fSDimitry Andric if (TargetIsThumb != InstrIsBlx) { 548*5f757f3fSDimitry Andric if (LLVM_LIKELY(TargetIsThumb)) { 549*5f757f3fSDimitry Andric // Change opcode BL -> BLX 550*5f757f3fSDimitry Andric R.Wd = R.Wd | FixupInfo<Arm_Call>::BitBlx; 551*5f757f3fSDimitry Andric R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitH; 552*5f757f3fSDimitry Andric } else { 553*5f757f3fSDimitry Andric // Change opcode BLX -> BL 554*5f757f3fSDimitry Andric R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitBlx; 555*5f757f3fSDimitry Andric } 556*5f757f3fSDimitry Andric } 557*5f757f3fSDimitry Andric 558*5f757f3fSDimitry Andric if (!isInt<26>(Value)) 559*5f757f3fSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 560*5f757f3fSDimitry Andric writeImmediate<Arm_Call>(R, encodeImmBA1BlA1BlxA2(Value)); 561*5f757f3fSDimitry Andric 562*5f757f3fSDimitry Andric return Error::success(); 563*5f757f3fSDimitry Andric } 564*5f757f3fSDimitry Andric case Arm_MovwAbsNC: { 565*5f757f3fSDimitry Andric uint16_t Value = (TargetAddress + Addend) & 0xffff; 566*5f757f3fSDimitry Andric writeImmediate<Arm_MovwAbsNC>(R, encodeImmMovtA1MovwA2(Value)); 567*5f757f3fSDimitry Andric return Error::success(); 568*5f757f3fSDimitry Andric } 569*5f757f3fSDimitry Andric case Arm_MovtAbs: { 570*5f757f3fSDimitry Andric uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 571*5f757f3fSDimitry Andric writeImmediate<Arm_MovtAbs>(R, encodeImmMovtA1MovwA2(Value)); 572*5f757f3fSDimitry Andric return Error::success(); 573*5f757f3fSDimitry Andric } 57406c3fb27SDimitry Andric default: 57506c3fb27SDimitry Andric return make_error<JITLinkError>( 57606c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 57706c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 57806c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 57906c3fb27SDimitry Andric } 58006c3fb27SDimitry Andric } 58106c3fb27SDimitry Andric 58206c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, 58306c3fb27SDimitry Andric const ArmConfig &ArmCfg) { 58406c3fb27SDimitry Andric WritableThumbRelocation R(B.getAlreadyMutableContent().data() + 58506c3fb27SDimitry Andric E.getOffset()); 58606c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 587*5f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 588*5f757f3fSDimitry Andric return Err; 589*5f757f3fSDimitry Andric 59006c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 59106c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 59206c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 59306c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 59406c3fb27SDimitry Andric 59506c3fb27SDimitry Andric switch (Kind) { 59606c3fb27SDimitry Andric case Thumb_Jump24: { 597*5f757f3fSDimitry Andric if (!hasTargetFlags(TargetSymbol, ThumbSymbol)) 59806c3fb27SDimitry Andric return make_error<JITLinkError>("Branch relocation needs interworking " 59906c3fb27SDimitry Andric "stub when bridging to ARM: " + 60006c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 60106c3fb27SDimitry Andric 60206c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 60306c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 60406c3fb27SDimitry Andric if (!isInt<25>(Value)) 60506c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 60606c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 60706c3fb27SDimitry Andric } else { 60806c3fb27SDimitry Andric if (!isInt<22>(Value)) 60906c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 61006c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value)); 61106c3fb27SDimitry Andric } 61206c3fb27SDimitry Andric 61306c3fb27SDimitry Andric return Error::success(); 61406c3fb27SDimitry Andric } 61506c3fb27SDimitry Andric 61606c3fb27SDimitry Andric case Thumb_Call: { 61706c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 61806c3fb27SDimitry Andric 61906c3fb27SDimitry Andric // The call instruction itself is Thumb. The call destination can either be 62006c3fb27SDimitry Andric // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm. 621*5f757f3fSDimitry Andric bool TargetIsArm = !hasTargetFlags(TargetSymbol, ThumbSymbol); 62206c3fb27SDimitry Andric bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0; 62306c3fb27SDimitry Andric if (TargetIsArm != InstrIsBlx) { 62406c3fb27SDimitry Andric if (LLVM_LIKELY(TargetIsArm)) { 625*5f757f3fSDimitry Andric // Change opcode BL -> BLX and fix range value: account for 4-byte 62606c3fb27SDimitry Andric // aligned destination while instruction may only be 2-byte aligned 62706c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 62806c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH; 62906c3fb27SDimitry Andric Value = alignTo(Value, 4); 63006c3fb27SDimitry Andric } else { 631*5f757f3fSDimitry Andric // Change opcode BLX -> BL 63206c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 63306c3fb27SDimitry Andric } 63406c3fb27SDimitry Andric } 63506c3fb27SDimitry Andric 63606c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 63706c3fb27SDimitry Andric if (!isInt<25>(Value)) 63806c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 63906c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 64006c3fb27SDimitry Andric } else { 64106c3fb27SDimitry Andric if (!isInt<22>(Value)) 64206c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 64306c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value)); 64406c3fb27SDimitry Andric } 64506c3fb27SDimitry Andric 64606c3fb27SDimitry Andric assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) || 64706c3fb27SDimitry Andric (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) && 64806c3fb27SDimitry Andric "Opcode BLX implies H bit is clear (avoid UB in BLX T2)"); 64906c3fb27SDimitry Andric return Error::success(); 65006c3fb27SDimitry Andric } 65106c3fb27SDimitry Andric 65206c3fb27SDimitry Andric case Thumb_MovwAbsNC: { 65306c3fb27SDimitry Andric uint16_t Value = (TargetAddress + Addend) & 0xffff; 65406c3fb27SDimitry Andric writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value)); 65506c3fb27SDimitry Andric return Error::success(); 65606c3fb27SDimitry Andric } 65706c3fb27SDimitry Andric case Thumb_MovtAbs: { 65806c3fb27SDimitry Andric uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 65906c3fb27SDimitry Andric writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value)); 66006c3fb27SDimitry Andric return Error::success(); 66106c3fb27SDimitry Andric } 662*5f757f3fSDimitry Andric case Thumb_MovwPrelNC: { 663*5f757f3fSDimitry Andric uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff); 664*5f757f3fSDimitry Andric writeImmediate<Thumb_MovwPrelNC>(R, encodeImmMovtT1MovwT3(Value)); 665*5f757f3fSDimitry Andric return Error::success(); 666*5f757f3fSDimitry Andric } 667*5f757f3fSDimitry Andric case Thumb_MovtPrel: { 668*5f757f3fSDimitry Andric uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff); 669*5f757f3fSDimitry Andric writeImmediate<Thumb_MovtPrel>(R, encodeImmMovtT1MovwT3(Value)); 670*5f757f3fSDimitry Andric return Error::success(); 671*5f757f3fSDimitry Andric } 67206c3fb27SDimitry Andric 67306c3fb27SDimitry Andric default: 67406c3fb27SDimitry Andric return make_error<JITLinkError>( 67506c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 67606c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 67706c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 67806c3fb27SDimitry Andric } 67906c3fb27SDimitry Andric } 68006c3fb27SDimitry Andric 68106c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = { 68206c3fb27SDimitry Andric 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit 68306c3fb27SDimitry Andric 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit 68406c3fb27SDimitry Andric 0x60, 0x47 // bx r12 68506c3fb27SDimitry Andric }; 68606c3fb27SDimitry Andric 68706c3fb27SDimitry Andric template <> 68806c3fb27SDimitry Andric Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) { 68906c3fb27SDimitry Andric constexpr uint64_t Alignment = 4; 69006c3fb27SDimitry Andric Block &B = addStub(G, Thumbv7ABS, Alignment); 69106c3fb27SDimitry Andric LLVM_DEBUG({ 69206c3fb27SDimitry Andric const char *StubPtr = B.getContent().data(); 69306c3fb27SDimitry Andric HalfWords Reg12 = encodeRegMovtT1MovwT3(12); 69406c3fb27SDimitry Andric assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && 69506c3fb27SDimitry Andric checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && 69606c3fb27SDimitry Andric "Linker generated stubs may only corrupt register r12 (IP)"); 69706c3fb27SDimitry Andric }); 69806c3fb27SDimitry Andric B.addEdge(Thumb_MovwAbsNC, 0, Target, 0); 69906c3fb27SDimitry Andric B.addEdge(Thumb_MovtAbs, 4, Target, 0); 70006c3fb27SDimitry Andric Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false); 70106c3fb27SDimitry Andric Stub.setTargetFlags(ThumbSymbol); 70206c3fb27SDimitry Andric return Stub; 70306c3fb27SDimitry Andric } 70406c3fb27SDimitry Andric 70506c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) { 70606c3fb27SDimitry Andric #define KIND_NAME_CASE(K) \ 70706c3fb27SDimitry Andric case K: \ 70806c3fb27SDimitry Andric return #K; 70906c3fb27SDimitry Andric 71006c3fb27SDimitry Andric switch (K) { 71106c3fb27SDimitry Andric KIND_NAME_CASE(Data_Delta32) 712*5f757f3fSDimitry Andric KIND_NAME_CASE(Data_Pointer32) 71306c3fb27SDimitry Andric KIND_NAME_CASE(Arm_Call) 714*5f757f3fSDimitry Andric KIND_NAME_CASE(Arm_Jump24) 715*5f757f3fSDimitry Andric KIND_NAME_CASE(Arm_MovwAbsNC) 716*5f757f3fSDimitry Andric KIND_NAME_CASE(Arm_MovtAbs) 71706c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Call) 71806c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Jump24) 71906c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovwAbsNC) 72006c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovtAbs) 721*5f757f3fSDimitry Andric KIND_NAME_CASE(Thumb_MovwPrelNC) 722*5f757f3fSDimitry Andric KIND_NAME_CASE(Thumb_MovtPrel) 72306c3fb27SDimitry Andric default: 72406c3fb27SDimitry Andric return getGenericEdgeKindName(K); 72506c3fb27SDimitry Andric } 72606c3fb27SDimitry Andric #undef KIND_NAME_CASE 72706c3fb27SDimitry Andric } 72806c3fb27SDimitry Andric 72906c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) { 73006c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K) \ 73106c3fb27SDimitry Andric case K: \ 73206c3fb27SDimitry Andric return #K; 73306c3fb27SDimitry Andric 73406c3fb27SDimitry Andric using namespace ARMBuildAttrs; 73506c3fb27SDimitry Andric switch (K) { 73606c3fb27SDimitry Andric CPUARCH_NAME_CASE(Pre_v4) 73706c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4) 73806c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4T) 73906c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5T) 74006c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TE) 74106c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TEJ) 74206c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6) 74306c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6KZ) 74406c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6T2) 74506c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6K) 74606c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7) 74706c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6_M) 74806c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6S_M) 74906c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7E_M) 75006c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_A) 75106c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_R) 75206c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Base) 75306c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Main) 75406c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_1_M_Main) 75506c3fb27SDimitry Andric CPUARCH_NAME_CASE(v9_A) 75606c3fb27SDimitry Andric } 75706c3fb27SDimitry Andric llvm_unreachable("Missing CPUArch in switch?"); 75806c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE 75906c3fb27SDimitry Andric } 76006c3fb27SDimitry Andric 76106c3fb27SDimitry Andric } // namespace aarch32 76206c3fb27SDimitry Andric } // namespace jitlink 76306c3fb27SDimitry Andric } // namespace llvm 764