15c1d160cSStefan Gränitz //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===// 25c1d160cSStefan Gränitz // 35c1d160cSStefan Gränitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45c1d160cSStefan Gränitz // See https://llvm.org/LICENSE.txt for license information. 55c1d160cSStefan Gränitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65c1d160cSStefan Gränitz // 75c1d160cSStefan Gränitz //===----------------------------------------------------------------------===// 85c1d160cSStefan Gränitz // 95c1d160cSStefan Gränitz // Generic utilities for graphs representing arm/thumb objects. 105c1d160cSStefan Gränitz // 115c1d160cSStefan Gränitz //===----------------------------------------------------------------------===// 125c1d160cSStefan Gränitz 135c1d160cSStefan Gränitz #include "llvm/ExecutionEngine/JITLink/aarch32.h" 145c1d160cSStefan Gränitz 155c1d160cSStefan Gränitz #include "llvm/ADT/StringExtras.h" 165c1d160cSStefan Gränitz #include "llvm/ExecutionEngine/JITLink/JITLink.h" 17e5ca202eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h" 185c1d160cSStefan Gränitz #include "llvm/Support/Endian.h" 19b86420c6SStefan Gränitz #include "llvm/Support/ManagedStatic.h" 205c1d160cSStefan Gränitz #include "llvm/Support/MathExtras.h" 215c1d160cSStefan Gränitz 225c1d160cSStefan Gränitz #define DEBUG_TYPE "jitlink" 235c1d160cSStefan Gränitz 245c1d160cSStefan Gränitz namespace llvm { 255c1d160cSStefan Gränitz namespace jitlink { 265c1d160cSStefan Gränitz namespace aarch32 { 275c1d160cSStefan Gränitz 289c017a99SEymen Ünay /// Check whether the given target flags are set for this Symbol. 299c017a99SEymen Ünay bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags) { 309c017a99SEymen Ünay return static_cast<TargetFlagsType>(Sym.getTargetFlags()) & Flags; 319c017a99SEymen Ünay } 329c017a99SEymen Ünay 335c1d160cSStefan Gränitz /// Encode 22-bit immediate value for branch instructions without J1J2 range 345c1d160cSStefan Gränitz /// extension (formats B T4, BL T1 and BLX T2). 355c1d160cSStefan Gränitz /// 365c1d160cSStefan Gränitz /// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ] 375c1d160cSStefan Gränitz /// J1^ ^J2 will always be 1 385c1d160cSStefan Gränitz /// 395c1d160cSStefan Gränitz HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) { 405c1d160cSStefan Gränitz constexpr uint32_t J1J2 = 0x2800; 415c1d160cSStefan Gränitz uint32_t Imm11H = (Value >> 12) & 0x07ff; 425c1d160cSStefan Gränitz uint32_t Imm11L = (Value >> 1) & 0x07ff; 435c1d160cSStefan Gränitz return HalfWords{Imm11H, Imm11L | J1J2}; 445c1d160cSStefan Gränitz } 455c1d160cSStefan Gränitz 465c1d160cSStefan Gränitz /// Decode 22-bit immediate value for branch instructions without J1J2 range 475c1d160cSStefan Gränitz /// extension (formats B T4, BL T1 and BLX T2). 485c1d160cSStefan Gränitz /// 495c1d160cSStefan Gränitz /// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0 505c1d160cSStefan Gränitz /// J1^ ^J2 will always be 1 515c1d160cSStefan Gränitz /// 525c1d160cSStefan Gränitz int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) { 535c1d160cSStefan Gränitz uint32_t Imm11H = Hi & 0x07ff; 545c1d160cSStefan Gränitz uint32_t Imm11L = Lo & 0x07ff; 555c1d160cSStefan Gränitz return SignExtend64<22>(Imm11H << 12 | Imm11L << 1); 565c1d160cSStefan Gränitz } 575c1d160cSStefan Gränitz 585c1d160cSStefan Gränitz /// Encode 25-bit immediate value for branch instructions with J1J2 range 595c1d160cSStefan Gränitz /// extension (formats B T4, BL T1 and BLX T2). 605c1d160cSStefan Gränitz /// 615c1d160cSStefan Gränitz /// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ] 625c1d160cSStefan Gränitz /// 635c1d160cSStefan Gränitz HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) { 645c1d160cSStefan Gränitz uint32_t S = (Value >> 14) & 0x0400; 655c1d160cSStefan Gränitz uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000); 665c1d160cSStefan Gränitz uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800); 675c1d160cSStefan Gränitz uint32_t Imm10 = (Value >> 12) & 0x03ff; 685c1d160cSStefan Gränitz uint32_t Imm11 = (Value >> 1) & 0x07ff; 695c1d160cSStefan Gränitz return HalfWords{S | Imm10, J1 | J2 | Imm11}; 705c1d160cSStefan Gränitz } 715c1d160cSStefan Gränitz 725c1d160cSStefan Gränitz /// Decode 25-bit immediate value for branch instructions with J1J2 range 735c1d160cSStefan Gränitz /// extension (formats B T4, BL T1 and BLX T2). 745c1d160cSStefan Gränitz /// 755c1d160cSStefan Gränitz /// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0 765c1d160cSStefan Gränitz /// 775c1d160cSStefan Gränitz int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) { 785c1d160cSStefan Gränitz uint32_t S = Hi & 0x0400; 795c1d160cSStefan Gränitz uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000; 805c1d160cSStefan Gränitz uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000; 815c1d160cSStefan Gränitz uint32_t Imm10 = Hi & 0x03ff; 825c1d160cSStefan Gränitz uint32_t Imm11 = Lo & 0x07ff; 835c1d160cSStefan Gränitz return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1); 845c1d160cSStefan Gränitz } 855c1d160cSStefan Gränitz 86142c89c3SEymen Ünay /// Encode 26-bit immediate value for branch instructions 87142c89c3SEymen Ünay /// (formats B A1, BL A1 and BLX A2). 88142c89c3SEymen Ünay /// 89142c89c3SEymen Ünay /// Imm24:00 -> 00000000:Imm24 90142c89c3SEymen Ünay /// 91142c89c3SEymen Ünay uint32_t encodeImmBA1BlA1BlxA2(int64_t Value) { 92142c89c3SEymen Ünay return (Value >> 2) & 0x00ffffff; 93142c89c3SEymen Ünay } 94142c89c3SEymen Ünay 95142c89c3SEymen Ünay /// Decode 26-bit immediate value for branch instructions 96142c89c3SEymen Ünay /// (formats B A1, BL A1 and BLX A2). 97142c89c3SEymen Ünay /// 98142c89c3SEymen Ünay /// 00000000:Imm24 -> Imm24:00 99142c89c3SEymen Ünay /// 100142c89c3SEymen Ünay int64_t decodeImmBA1BlA1BlxA2(int64_t Value) { 101142c89c3SEymen Ünay return SignExtend64<26>((Value & 0x00ffffff) << 2); 102142c89c3SEymen Ünay } 103142c89c3SEymen Ünay 1045c1d160cSStefan Gränitz /// Encode 16-bit immediate value for move instruction formats MOVT T1 and 1055c1d160cSStefan Gränitz /// MOVW T3. 1065c1d160cSStefan Gränitz /// 1075c1d160cSStefan Gränitz /// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] 1085c1d160cSStefan Gränitz /// 1095c1d160cSStefan Gränitz HalfWords encodeImmMovtT1MovwT3(uint16_t Value) { 1105c1d160cSStefan Gränitz uint32_t Imm4 = (Value >> 12) & 0x0f; 1115c1d160cSStefan Gränitz uint32_t Imm1 = (Value >> 11) & 0x01; 1125c1d160cSStefan Gränitz uint32_t Imm3 = (Value >> 8) & 0x07; 1135c1d160cSStefan Gränitz uint32_t Imm8 = Value & 0xff; 1145c1d160cSStefan Gränitz return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8}; 1155c1d160cSStefan Gränitz } 1165c1d160cSStefan Gränitz 1175c1d160cSStefan Gränitz /// Decode 16-bit immediate value from move instruction formats MOVT T1 and 1185c1d160cSStefan Gränitz /// MOVW T3. 1195c1d160cSStefan Gränitz /// 1205c1d160cSStefan Gränitz /// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8 1215c1d160cSStefan Gränitz /// 1225c1d160cSStefan Gränitz uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 1235c1d160cSStefan Gränitz uint32_t Imm4 = Hi & 0x0f; 1245c1d160cSStefan Gränitz uint32_t Imm1 = (Hi >> 10) & 0x01; 1255c1d160cSStefan Gränitz uint32_t Imm3 = (Lo >> 12) & 0x07; 1265c1d160cSStefan Gränitz uint32_t Imm8 = Lo & 0xff; 1275c1d160cSStefan Gränitz uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8; 1285c1d160cSStefan Gränitz assert(Imm16 <= 0xffff && "Decoded value out-of-range"); 1295c1d160cSStefan Gränitz return Imm16; 1305c1d160cSStefan Gränitz } 1315c1d160cSStefan Gränitz 1325c1d160cSStefan Gränitz /// Encode register ID for instruction formats MOVT T1 and MOVW T3. 1335c1d160cSStefan Gränitz /// 1345c1d160cSStefan Gränitz /// Rd4 -> [0000000000000000, 0000:Rd4:00000000] 1355c1d160cSStefan Gränitz /// 1365c1d160cSStefan Gränitz HalfWords encodeRegMovtT1MovwT3(int64_t Value) { 1375c1d160cSStefan Gränitz uint32_t Rd4 = (Value & 0x0f) << 8; 1385c1d160cSStefan Gränitz return HalfWords{0, Rd4}; 1395c1d160cSStefan Gränitz } 1405c1d160cSStefan Gränitz 1415c1d160cSStefan Gränitz /// Decode register ID from instruction formats MOVT T1 and MOVW T3. 1425c1d160cSStefan Gränitz /// 1435c1d160cSStefan Gränitz /// [0000000000000000, 0000:Rd4:00000000] -> Rd4 1445c1d160cSStefan Gränitz /// 1455c1d160cSStefan Gränitz int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 1465c1d160cSStefan Gränitz uint32_t Rd4 = (Lo >> 8) & 0x0f; 1475c1d160cSStefan Gränitz return Rd4; 1485c1d160cSStefan Gränitz } 1495c1d160cSStefan Gränitz 150e575b7cbSEymen Ünay /// Encode 16-bit immediate value for move instruction formats MOVT A1 and 151e575b7cbSEymen Ünay /// MOVW A2. 152e575b7cbSEymen Ünay /// 153e575b7cbSEymen Ünay /// Imm4:Imm12 -> 000000000000:Imm4:0000:Imm12 154e575b7cbSEymen Ünay /// 155e575b7cbSEymen Ünay uint32_t encodeImmMovtA1MovwA2(uint16_t Value) { 156e575b7cbSEymen Ünay uint32_t Imm4 = (Value >> 12) & 0x0f; 157e575b7cbSEymen Ünay uint32_t Imm12 = Value & 0x0fff; 158e575b7cbSEymen Ünay return (Imm4 << 16) | Imm12; 159e575b7cbSEymen Ünay } 160e575b7cbSEymen Ünay 161e575b7cbSEymen Ünay /// Decode 16-bit immediate value for move instruction formats MOVT A1 and 162e575b7cbSEymen Ünay /// MOVW A2. 163e575b7cbSEymen Ünay /// 164e575b7cbSEymen Ünay /// 000000000000:Imm4:0000:Imm12 -> Imm4:Imm12 165e575b7cbSEymen Ünay /// 166e575b7cbSEymen Ünay uint16_t decodeImmMovtA1MovwA2(uint64_t Value) { 167e575b7cbSEymen Ünay uint32_t Imm4 = (Value >> 16) & 0x0f; 168e575b7cbSEymen Ünay uint32_t Imm12 = Value & 0x0fff; 169e575b7cbSEymen Ünay return (Imm4 << 12) | Imm12; 170e575b7cbSEymen Ünay } 171e575b7cbSEymen Ünay 172e575b7cbSEymen Ünay /// Encode register ID for instruction formats MOVT A1 and 173e575b7cbSEymen Ünay /// MOVW A2. 174e575b7cbSEymen Ünay /// 175e575b7cbSEymen Ünay /// Rd4 -> 0000000000000000:Rd4:000000000000 176e575b7cbSEymen Ünay /// 177e575b7cbSEymen Ünay uint32_t encodeRegMovtA1MovwA2(int64_t Value) { 178e575b7cbSEymen Ünay uint32_t Rd4 = (Value & 0x00000f) << 12; 179e575b7cbSEymen Ünay return Rd4; 180e575b7cbSEymen Ünay } 181e575b7cbSEymen Ünay 182e575b7cbSEymen Ünay /// Decode register ID for instruction formats MOVT A1 and 183e575b7cbSEymen Ünay /// MOVW A2. 184e575b7cbSEymen Ünay /// 185e575b7cbSEymen Ünay /// 0000000000000000:Rd4:000000000000 -> Rd4 186e575b7cbSEymen Ünay /// 187e575b7cbSEymen Ünay int64_t decodeRegMovtA1MovwA2(uint64_t Value) { 188e575b7cbSEymen Ünay uint32_t Rd4 = (Value >> 12) & 0x00000f; 189e575b7cbSEymen Ünay return Rd4; 190e575b7cbSEymen Ünay } 191e575b7cbSEymen Ünay 192b86420c6SStefan Gränitz namespace { 193b86420c6SStefan Gränitz 1945c1d160cSStefan Gränitz /// 32-bit Thumb instructions are stored as two little-endian halfwords. 1955c1d160cSStefan Gränitz /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi), 1965c1d160cSStefan Gränitz /// followed by bytes A+3, A+2 in the second halfword (Lo). 1975c1d160cSStefan Gränitz struct WritableThumbRelocation { 1985c1d160cSStefan Gränitz /// Create a writable reference to a Thumb32 fixup. 1995c1d160cSStefan Gränitz WritableThumbRelocation(char *FixupPtr) 2005c1d160cSStefan Gränitz : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)}, 2015c1d160cSStefan Gränitz Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {} 2025c1d160cSStefan Gränitz 2035c1d160cSStefan Gränitz support::ulittle16_t &Hi; // First halfword 2045c1d160cSStefan Gränitz support::ulittle16_t &Lo; // Second halfword 2055c1d160cSStefan Gränitz }; 2065c1d160cSStefan Gränitz 2075c1d160cSStefan Gränitz struct ThumbRelocation { 2085c1d160cSStefan Gränitz /// Create a read-only reference to a Thumb32 fixup. 2095c1d160cSStefan Gränitz ThumbRelocation(const char *FixupPtr) 2105c1d160cSStefan Gränitz : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)}, 2115c1d160cSStefan Gränitz Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {} 2125c1d160cSStefan Gränitz 2135c1d160cSStefan Gränitz /// Create a read-only Thumb32 fixup from a writeable one. 2145c1d160cSStefan Gränitz ThumbRelocation(WritableThumbRelocation &Writable) 2155c1d160cSStefan Gränitz : Hi{Writable.Hi}, Lo(Writable.Lo) {} 2165c1d160cSStefan Gränitz 2175c1d160cSStefan Gränitz const support::ulittle16_t &Hi; // First halfword 2185c1d160cSStefan Gränitz const support::ulittle16_t &Lo; // Second halfword 2195c1d160cSStefan Gränitz }; 2205c1d160cSStefan Gränitz 221142c89c3SEymen Ünay struct WritableArmRelocation { 222142c89c3SEymen Ünay WritableArmRelocation(char *FixupPtr) 223142c89c3SEymen Ünay : Wd{*reinterpret_cast<support::ulittle32_t *>(FixupPtr)} {} 224142c89c3SEymen Ünay 225142c89c3SEymen Ünay support::ulittle32_t &Wd; 226142c89c3SEymen Ünay }; 227142c89c3SEymen Ünay 228142c89c3SEymen Ünay struct ArmRelocation { 229142c89c3SEymen Ünay ArmRelocation(const char *FixupPtr) 230142c89c3SEymen Ünay : Wd{*reinterpret_cast<const support::ulittle32_t *>(FixupPtr)} {} 231142c89c3SEymen Ünay 232142c89c3SEymen Ünay ArmRelocation(WritableArmRelocation &Writable) : Wd{Writable.Wd} {} 233142c89c3SEymen Ünay 234142c89c3SEymen Ünay const support::ulittle32_t &Wd; 235142c89c3SEymen Ünay }; 236142c89c3SEymen Ünay 2375c1d160cSStefan Gränitz Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, 2385c1d160cSStefan Gränitz Edge::Kind Kind) { 2395c1d160cSStefan Gränitz return make_error<JITLinkError>( 24021ee9e4bSStefan Gränitz formatv("Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}", 2414cb0b7ceSStefan Gränitz static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo), 2424cb0b7ceSStefan Gränitz G.getEdgeKindName(Kind))); 2435c1d160cSStefan Gränitz } 2445c1d160cSStefan Gränitz 245142c89c3SEymen Ünay Error makeUnexpectedOpcodeError(const LinkGraph &G, const ArmRelocation &R, 246142c89c3SEymen Ünay Edge::Kind Kind) { 247142c89c3SEymen Ünay return make_error<JITLinkError>( 24821ee9e4bSStefan Gränitz formatv("Invalid opcode {0:x8} for relocation: {1}", 249142c89c3SEymen Ünay static_cast<uint32_t>(R.Wd), G.getEdgeKindName(Kind))); 250142c89c3SEymen Ünay } 251142c89c3SEymen Ünay 252b86420c6SStefan Gränitz template <EdgeKind_aarch32 K> constexpr bool isArm() { 253b86420c6SStefan Gränitz return FirstArmRelocation <= K && K <= LastArmRelocation; 254b86420c6SStefan Gränitz } 255b86420c6SStefan Gränitz template <EdgeKind_aarch32 K> constexpr bool isThumb() { 256b86420c6SStefan Gränitz return FirstThumbRelocation <= K && K <= LastThumbRelocation; 2575c1d160cSStefan Gränitz } 2585c1d160cSStefan Gränitz 259b86420c6SStefan Gränitz template <EdgeKind_aarch32 K> static bool checkOpcodeArm(uint32_t Wd) { 260b86420c6SStefan Gränitz return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode; 261b86420c6SStefan Gränitz } 262b86420c6SStefan Gränitz 263b86420c6SStefan Gränitz template <EdgeKind_aarch32 K> 264b86420c6SStefan Gränitz static bool checkOpcodeThumb(uint16_t Hi, uint16_t Lo) { 265b86420c6SStefan Gränitz return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi && 266b86420c6SStefan Gränitz (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo; 267b86420c6SStefan Gränitz } 268b86420c6SStefan Gränitz 269b86420c6SStefan Gränitz class FixupInfoTable { 270b86420c6SStefan Gränitz static constexpr size_t Items = LastRelocation + 1; 271b86420c6SStefan Gränitz 272b86420c6SStefan Gränitz public: 273b86420c6SStefan Gränitz FixupInfoTable() { 274b86420c6SStefan Gränitz populateEntries<FirstArmRelocation, LastArmRelocation>(); 275b86420c6SStefan Gränitz populateEntries<FirstThumbRelocation, LastThumbRelocation>(); 276b86420c6SStefan Gränitz } 277b86420c6SStefan Gränitz 278b86420c6SStefan Gränitz const FixupInfoBase *getEntry(Edge::Kind K) { 279b86420c6SStefan Gränitz assert(K < Data.size() && "Index out of bounds"); 280b86420c6SStefan Gränitz return Data.at(K).get(); 281b86420c6SStefan Gränitz } 282b86420c6SStefan Gränitz 283b86420c6SStefan Gränitz private: 284b86420c6SStefan Gränitz template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK> void populateEntries() { 285b86420c6SStefan Gränitz assert(K < Data.size() && "Index out of range"); 286b86420c6SStefan Gränitz assert(Data.at(K) == nullptr && "Initialized entries are immutable"); 287b86420c6SStefan Gränitz Data[K] = initEntry<K>(); 288b86420c6SStefan Gränitz if constexpr (K < LastK) { 289b86420c6SStefan Gränitz constexpr auto Next = static_cast<EdgeKind_aarch32>(K + 1); 290b86420c6SStefan Gränitz populateEntries<Next, LastK>(); 291b86420c6SStefan Gränitz } 292b86420c6SStefan Gränitz } 293b86420c6SStefan Gränitz 294b86420c6SStefan Gränitz template <EdgeKind_aarch32 K> 295b86420c6SStefan Gränitz static std::unique_ptr<FixupInfoBase> initEntry() { 296b86420c6SStefan Gränitz auto Entry = std::make_unique<FixupInfo<K>>(); 297b86420c6SStefan Gränitz static_assert(isArm<K>() != isThumb<K>(), "Classes are mutually exclusive"); 298b86420c6SStefan Gränitz if constexpr (isArm<K>()) 299b86420c6SStefan Gränitz Entry->checkOpcode = checkOpcodeArm<K>; 300b86420c6SStefan Gränitz if constexpr (isThumb<K>()) 301b86420c6SStefan Gränitz Entry->checkOpcode = checkOpcodeThumb<K>; 302b86420c6SStefan Gränitz return Entry; 303b86420c6SStefan Gränitz } 304b86420c6SStefan Gränitz 305b86420c6SStefan Gränitz private: 306b86420c6SStefan Gränitz std::array<std::unique_ptr<FixupInfoBase>, Items> Data; 307b86420c6SStefan Gränitz }; 308b86420c6SStefan Gränitz 309b86420c6SStefan Gränitz ManagedStatic<FixupInfoTable> DynFixupInfos; 310b86420c6SStefan Gränitz 311b86420c6SStefan Gränitz } // namespace 312b86420c6SStefan Gränitz 313b86420c6SStefan Gränitz static Error checkOpcode(LinkGraph &G, const ArmRelocation &R, 314b86420c6SStefan Gränitz Edge::Kind Kind) { 315b86420c6SStefan Gränitz assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation && 316b86420c6SStefan Gränitz "Edge kind must be Arm relocation"); 317b86420c6SStefan Gränitz const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind); 318b86420c6SStefan Gränitz const FixupInfoArm &Info = *static_cast<const FixupInfoArm *>(Entry); 319b86420c6SStefan Gränitz assert(Info.checkOpcode && "Opcode check is mandatory for Arm edges"); 320b86420c6SStefan Gränitz if (!Info.checkOpcode(R.Wd)) 321b86420c6SStefan Gränitz return makeUnexpectedOpcodeError(G, R, Kind); 322b86420c6SStefan Gränitz 323b86420c6SStefan Gränitz return Error::success(); 324b86420c6SStefan Gränitz } 325b86420c6SStefan Gränitz 326b86420c6SStefan Gränitz static Error checkOpcode(LinkGraph &G, const ThumbRelocation &R, 327b86420c6SStefan Gränitz Edge::Kind Kind) { 328b86420c6SStefan Gränitz assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation && 329b86420c6SStefan Gränitz "Edge kind must be Thumb relocation"); 330b86420c6SStefan Gränitz const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind); 331b86420c6SStefan Gränitz const FixupInfoThumb &Info = *static_cast<const FixupInfoThumb *>(Entry); 332b86420c6SStefan Gränitz assert(Info.checkOpcode && "Opcode check is mandatory for Thumb edges"); 333b86420c6SStefan Gränitz if (!Info.checkOpcode(R.Hi, R.Lo)) 334b86420c6SStefan Gränitz return makeUnexpectedOpcodeError(G, R, Kind); 335b86420c6SStefan Gränitz 336b86420c6SStefan Gränitz return Error::success(); 337b86420c6SStefan Gränitz } 338b86420c6SStefan Gränitz 339b86420c6SStefan Gränitz const FixupInfoBase *FixupInfoBase::getDynFixupInfo(Edge::Kind K) { 340b86420c6SStefan Gränitz return DynFixupInfos->getEntry(K); 341142c89c3SEymen Ünay } 342142c89c3SEymen Ünay 3435c1d160cSStefan Gränitz template <EdgeKind_aarch32 Kind> 3445c1d160cSStefan Gränitz bool checkRegister(const ThumbRelocation &R, HalfWords Reg) { 3455c1d160cSStefan Gränitz uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi; 3465c1d160cSStefan Gränitz uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo; 3475c1d160cSStefan Gränitz return Hi == Reg.Hi && Lo == Reg.Lo; 3485c1d160cSStefan Gränitz } 3495c1d160cSStefan Gränitz 3505c1d160cSStefan Gränitz template <EdgeKind_aarch32 Kind> 351142c89c3SEymen Ünay bool checkRegister(const ArmRelocation &R, uint32_t Reg) { 352142c89c3SEymen Ünay uint32_t Wd = R.Wd & FixupInfo<Kind>::RegMask; 353142c89c3SEymen Ünay return Wd == Reg; 354142c89c3SEymen Ünay } 355142c89c3SEymen Ünay 356142c89c3SEymen Ünay template <EdgeKind_aarch32 Kind> 357dce17939SLang Hames void writeRegister(WritableThumbRelocation &R, HalfWords Reg) { 3585c1d160cSStefan Gränitz static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask; 3593e7cd5eaSEymen Ünay assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Lo & Reg.Lo) == Reg.Lo && 3605c1d160cSStefan Gränitz "Value bits exceed bit range of given mask"); 3615c1d160cSStefan Gränitz R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi; 3625c1d160cSStefan Gränitz R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo; 3635c1d160cSStefan Gränitz } 3645c1d160cSStefan Gränitz 3655c1d160cSStefan Gränitz template <EdgeKind_aarch32 Kind> 366142c89c3SEymen Ünay void writeRegister(WritableArmRelocation &R, uint32_t Reg) { 367142c89c3SEymen Ünay static constexpr uint32_t Mask = FixupInfo<Kind>::RegMask; 368142c89c3SEymen Ünay assert((Mask & Reg) == Reg && "Value bits exceed bit range of given mask"); 369142c89c3SEymen Ünay R.Wd = (R.Wd & ~Mask) | Reg; 370142c89c3SEymen Ünay } 371142c89c3SEymen Ünay 372142c89c3SEymen Ünay template <EdgeKind_aarch32 Kind> 3735c1d160cSStefan Gränitz void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) { 3745c1d160cSStefan Gränitz static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask; 3753e7cd5eaSEymen Ünay assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo && 3765c1d160cSStefan Gränitz "Value bits exceed bit range of given mask"); 3775c1d160cSStefan Gränitz R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi; 3785c1d160cSStefan Gränitz R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo; 3795c1d160cSStefan Gränitz } 3805c1d160cSStefan Gränitz 381142c89c3SEymen Ünay template <EdgeKind_aarch32 Kind> 382142c89c3SEymen Ünay void writeImmediate(WritableArmRelocation &R, uint32_t Imm) { 383142c89c3SEymen Ünay static constexpr uint32_t Mask = FixupInfo<Kind>::ImmMask; 384142c89c3SEymen Ünay assert((Mask & Imm) == Imm && "Value bits exceed bit range of given mask"); 385142c89c3SEymen Ünay R.Wd = (R.Wd & ~Mask) | Imm; 386142c89c3SEymen Ünay } 387142c89c3SEymen Ünay 388808caa9dSStefan Gränitz Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset, 389808caa9dSStefan Gränitz Edge::Kind Kind) { 390e9706527SStefan Gränitz endianness Endian = G.getEndianness(); 3915c1d160cSStefan Gränitz const char *BlockWorkingMem = B.getContent().data(); 392808caa9dSStefan Gränitz const char *FixupPtr = BlockWorkingMem + Offset; 3935c1d160cSStefan Gränitz 3945c1d160cSStefan Gränitz switch (Kind) { 3955c1d160cSStefan Gränitz case Data_Delta32: 396a05a98a2SStefan Gränitz case Data_Pointer32: 397c4fc563bSStefan Gränitz case Data_RequestGOTAndTransformToDelta32: 39803df67e7SBenjamin Kramer return SignExtend64<32>(support::endian::read32(FixupPtr, Endian)); 3999577806bSStefan Gränitz case Data_PRel31: 4009577806bSStefan Gränitz return SignExtend64<31>(support::endian::read32(FixupPtr, Endian)); 4015c1d160cSStefan Gränitz default: 4025c1d160cSStefan Gränitz return make_error<JITLinkError>( 4035c1d160cSStefan Gränitz "In graph " + G.getName() + ", section " + B.getSection().getName() + 4045c1d160cSStefan Gränitz " can not read implicit addend for aarch32 edge kind " + 405808caa9dSStefan Gränitz G.getEdgeKindName(Kind)); 4065c1d160cSStefan Gränitz } 4075c1d160cSStefan Gränitz } 4085c1d160cSStefan Gränitz 409808caa9dSStefan Gränitz Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset, 410808caa9dSStefan Gränitz Edge::Kind Kind) { 411808caa9dSStefan Gränitz ArmRelocation R(B.getContent().data() + Offset); 412b86420c6SStefan Gränitz if (Error Err = checkOpcode(G, R, Kind)) 413b86420c6SStefan Gränitz return std::move(Err); 4145c1d160cSStefan Gränitz 4155c1d160cSStefan Gränitz switch (Kind) { 4165c1d160cSStefan Gränitz case Arm_Call: 41762f793ecSEymen Ünay case Arm_Jump24: 41862f793ecSEymen Ünay return decodeImmBA1BlA1BlxA2(R.Wd); 41962f793ecSEymen Ünay 420e575b7cbSEymen Ünay case Arm_MovtAbs: 421b86420c6SStefan Gränitz case Arm_MovwAbsNC: 422e575b7cbSEymen Ünay return decodeImmMovtA1MovwA2(R.Wd); 423e575b7cbSEymen Ünay 4245c1d160cSStefan Gränitz default: 4255c1d160cSStefan Gränitz return make_error<JITLinkError>( 4265c1d160cSStefan Gränitz "In graph " + G.getName() + ", section " + B.getSection().getName() + 4275c1d160cSStefan Gränitz " can not read implicit addend for aarch32 edge kind " + 428808caa9dSStefan Gränitz G.getEdgeKindName(Kind)); 4295c1d160cSStefan Gränitz } 4305c1d160cSStefan Gränitz } 4315c1d160cSStefan Gränitz 432808caa9dSStefan Gränitz Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset, 433808caa9dSStefan Gränitz Edge::Kind Kind, const ArmConfig &ArmCfg) { 434808caa9dSStefan Gränitz ThumbRelocation R(B.getContent().data() + Offset); 435b86420c6SStefan Gränitz if (Error Err = checkOpcode(G, R, Kind)) 436b86420c6SStefan Gränitz return std::move(Err); 4375c1d160cSStefan Gränitz 4385c1d160cSStefan Gränitz switch (Kind) { 4395c1d160cSStefan Gränitz case Thumb_Call: 4405c1d160cSStefan Gränitz case Thumb_Jump24: 4415c1d160cSStefan Gränitz return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 4425c1d160cSStefan Gränitz ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 4435c1d160cSStefan Gränitz : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 4445c1d160cSStefan Gränitz 4455c1d160cSStefan Gränitz case Thumb_MovwAbsNC: 44687081f1cSEymen Ünay case Thumb_MovwPrelNC: 4475c1d160cSStefan Gränitz // Initial addend is interpreted as a signed value 4485c1d160cSStefan Gränitz return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 4495c1d160cSStefan Gränitz 4505c1d160cSStefan Gränitz case Thumb_MovtAbs: 45187081f1cSEymen Ünay case Thumb_MovtPrel: 4525c1d160cSStefan Gränitz // Initial addend is interpreted as a signed value 4535c1d160cSStefan Gränitz return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 4545c1d160cSStefan Gränitz 4555c1d160cSStefan Gränitz default: 4565c1d160cSStefan Gränitz return make_error<JITLinkError>( 4575c1d160cSStefan Gränitz "In graph " + G.getName() + ", section " + B.getSection().getName() + 4585c1d160cSStefan Gränitz " can not read implicit addend for aarch32 edge kind " + 459808caa9dSStefan Gränitz G.getEdgeKindName(Kind)); 4605c1d160cSStefan Gränitz } 4615c1d160cSStefan Gränitz } 4625c1d160cSStefan Gränitz 4635c1d160cSStefan Gränitz Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) { 4645c1d160cSStefan Gränitz using namespace support; 4655c1d160cSStefan Gränitz 4665c1d160cSStefan Gränitz char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 4675c1d160cSStefan Gränitz char *FixupPtr = BlockWorkingMem + E.getOffset(); 4685c1d160cSStefan Gränitz 4695c1d160cSStefan Gränitz Edge::Kind Kind = E.getKind(); 4705c1d160cSStefan Gränitz uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 4715c1d160cSStefan Gränitz int64_t Addend = E.getAddend(); 4725c1d160cSStefan Gränitz Symbol &TargetSymbol = E.getTarget(); 4735c1d160cSStefan Gränitz uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 4745c1d160cSStefan Gränitz 4759577806bSStefan Gränitz // Data relocations have alignment 1, size 4 (except R_ARM_ABS8 and 4769577806bSStefan Gränitz // R_ARM_ABS16) and write the full 32-bit result (except R_ARM_PREL31). 4775c1d160cSStefan Gränitz switch (Kind) { 4785c1d160cSStefan Gränitz case Data_Delta32: { 4795c1d160cSStefan Gränitz int64_t Value = TargetAddress - FixupAddress + Addend; 4805c1d160cSStefan Gränitz if (!isInt<32>(Value)) 4815c1d160cSStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 482c4fc563bSStefan Gränitz if (LLVM_LIKELY(G.getEndianness() == endianness::little)) 483c4fc563bSStefan Gränitz endian::write32le(FixupPtr, Value); 484c4fc563bSStefan Gränitz else 485c4fc563bSStefan Gränitz endian::write32be(FixupPtr, Value); 4865c1d160cSStefan Gränitz return Error::success(); 4875c1d160cSStefan Gränitz } 488a05a98a2SStefan Gränitz case Data_Pointer32: { 489a05a98a2SStefan Gränitz int64_t Value = TargetAddress + Addend; 490c4fc563bSStefan Gränitz if (!isUInt<32>(Value)) 491a05a98a2SStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 492c4fc563bSStefan Gränitz if (LLVM_LIKELY(G.getEndianness() == endianness::little)) 493c4fc563bSStefan Gränitz endian::write32le(FixupPtr, Value); 494c4fc563bSStefan Gränitz else 495c4fc563bSStefan Gränitz endian::write32be(FixupPtr, Value); 496a05a98a2SStefan Gränitz return Error::success(); 497a05a98a2SStefan Gränitz } 4989577806bSStefan Gränitz case Data_PRel31: { 4999577806bSStefan Gränitz int64_t Value = TargetAddress - FixupAddress + Addend; 5009577806bSStefan Gränitz if (!isInt<31>(Value)) 5019577806bSStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 5029577806bSStefan Gränitz if (LLVM_LIKELY(G.getEndianness() == endianness::little)) { 5039577806bSStefan Gränitz uint32_t MSB = endian::read32le(FixupPtr) & 0x80000000; 5049577806bSStefan Gränitz endian::write32le(FixupPtr, MSB | (Value & ~0x80000000)); 5059577806bSStefan Gränitz } else { 5069577806bSStefan Gränitz uint32_t MSB = endian::read32be(FixupPtr) & 0x80000000; 5079577806bSStefan Gränitz endian::write32be(FixupPtr, MSB | (Value & ~0x80000000)); 5089577806bSStefan Gränitz } 5099577806bSStefan Gränitz return Error::success(); 5109577806bSStefan Gränitz } 511c4fc563bSStefan Gränitz case Data_RequestGOTAndTransformToDelta32: 512c4fc563bSStefan Gränitz llvm_unreachable("Should be transformed"); 5135c1d160cSStefan Gränitz default: 5145c1d160cSStefan Gränitz return make_error<JITLinkError>( 5155c1d160cSStefan Gränitz "In graph " + G.getName() + ", section " + B.getSection().getName() + 5165c1d160cSStefan Gränitz " encountered unfixable aarch32 edge kind " + 5175c1d160cSStefan Gränitz G.getEdgeKindName(E.getKind())); 5185c1d160cSStefan Gränitz } 5195c1d160cSStefan Gränitz } 5205c1d160cSStefan Gränitz 5215c1d160cSStefan Gränitz Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) { 522142c89c3SEymen Ünay WritableArmRelocation R(B.getAlreadyMutableContent().data() + E.getOffset()); 5235c1d160cSStefan Gränitz Edge::Kind Kind = E.getKind(); 524b86420c6SStefan Gränitz if (Error Err = checkOpcode(G, R, Kind)) 525b86420c6SStefan Gränitz return Err; 526b86420c6SStefan Gränitz 527142c89c3SEymen Ünay uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 528142c89c3SEymen Ünay int64_t Addend = E.getAddend(); 529142c89c3SEymen Ünay Symbol &TargetSymbol = E.getTarget(); 530142c89c3SEymen Ünay uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 5315c1d160cSStefan Gränitz 5325c1d160cSStefan Gränitz switch (Kind) { 53362f793ecSEymen Ünay case Arm_Jump24: { 53462f793ecSEymen Ünay if (hasTargetFlags(TargetSymbol, ThumbSymbol)) 53562f793ecSEymen Ünay return make_error<JITLinkError>("Branch relocation needs interworking " 53662f793ecSEymen Ünay "stub when bridging to Thumb: " + 53762f793ecSEymen Ünay StringRef(G.getEdgeKindName(Kind))); 53862f793ecSEymen Ünay 53962f793ecSEymen Ünay int64_t Value = TargetAddress - FixupAddress + Addend; 54062f793ecSEymen Ünay 54162f793ecSEymen Ünay if (!isInt<26>(Value)) 54262f793ecSEymen Ünay return makeTargetOutOfRangeError(G, B, E); 54362f793ecSEymen Ünay writeImmediate<Arm_Jump24>(R, encodeImmBA1BlA1BlxA2(Value)); 54462f793ecSEymen Ünay 54562f793ecSEymen Ünay return Error::success(); 54662f793ecSEymen Ünay } 547142c89c3SEymen Ünay case Arm_Call: { 548142c89c3SEymen Ünay if ((R.Wd & FixupInfo<Arm_Call>::CondMask) != 549142c89c3SEymen Ünay FixupInfo<Arm_Call>::Unconditional) 550142c89c3SEymen Ünay return make_error<JITLinkError>("Relocation expects an unconditional " 551142c89c3SEymen Ünay "BL/BLX branch instruction: " + 5525c1d160cSStefan Gränitz StringRef(G.getEdgeKindName(Kind))); 553142c89c3SEymen Ünay 554142c89c3SEymen Ünay int64_t Value = TargetAddress - FixupAddress + Addend; 555142c89c3SEymen Ünay 556142c89c3SEymen Ünay // The call instruction itself is Arm. The call destination can either be 557142c89c3SEymen Ünay // Thumb or Arm. We use BL to stay in Arm and BLX to change to Thumb. 558142c89c3SEymen Ünay bool TargetIsThumb = hasTargetFlags(TargetSymbol, ThumbSymbol); 559142c89c3SEymen Ünay bool InstrIsBlx = (~R.Wd & FixupInfo<Arm_Call>::BitBlx) == 0; 560142c89c3SEymen Ünay if (TargetIsThumb != InstrIsBlx) { 561142c89c3SEymen Ünay if (LLVM_LIKELY(TargetIsThumb)) { 5621025189eSStefan Gränitz // Change opcode BL -> BLX 563142c89c3SEymen Ünay R.Wd = R.Wd | FixupInfo<Arm_Call>::BitBlx; 564142c89c3SEymen Ünay R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitH; 565142c89c3SEymen Ünay } else { 566142c89c3SEymen Ünay // Change opcode BLX -> BL 567142c89c3SEymen Ünay R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitBlx; 568142c89c3SEymen Ünay } 569142c89c3SEymen Ünay } 570142c89c3SEymen Ünay 571142c89c3SEymen Ünay if (!isInt<26>(Value)) 572142c89c3SEymen Ünay return makeTargetOutOfRangeError(G, B, E); 573142c89c3SEymen Ünay writeImmediate<Arm_Call>(R, encodeImmBA1BlA1BlxA2(Value)); 574142c89c3SEymen Ünay 575142c89c3SEymen Ünay return Error::success(); 576142c89c3SEymen Ünay } 577e575b7cbSEymen Ünay case Arm_MovwAbsNC: { 578e575b7cbSEymen Ünay uint16_t Value = (TargetAddress + Addend) & 0xffff; 579e575b7cbSEymen Ünay writeImmediate<Arm_MovwAbsNC>(R, encodeImmMovtA1MovwA2(Value)); 580e575b7cbSEymen Ünay return Error::success(); 581e575b7cbSEymen Ünay } 582e575b7cbSEymen Ünay case Arm_MovtAbs: { 583e575b7cbSEymen Ünay uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 584e575b7cbSEymen Ünay writeImmediate<Arm_MovtAbs>(R, encodeImmMovtA1MovwA2(Value)); 585e575b7cbSEymen Ünay return Error::success(); 586e575b7cbSEymen Ünay } 5875c1d160cSStefan Gränitz default: 5885c1d160cSStefan Gränitz return make_error<JITLinkError>( 5895c1d160cSStefan Gränitz "In graph " + G.getName() + ", section " + B.getSection().getName() + 5905c1d160cSStefan Gränitz " encountered unfixable aarch32 edge kind " + 5915c1d160cSStefan Gränitz G.getEdgeKindName(E.getKind())); 5925c1d160cSStefan Gränitz } 5935c1d160cSStefan Gränitz } 5945c1d160cSStefan Gränitz 5955c1d160cSStefan Gränitz Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, 5965c1d160cSStefan Gränitz const ArmConfig &ArmCfg) { 5975c1d160cSStefan Gränitz WritableThumbRelocation R(B.getAlreadyMutableContent().data() + 5985c1d160cSStefan Gränitz E.getOffset()); 5995c1d160cSStefan Gränitz Edge::Kind Kind = E.getKind(); 600b86420c6SStefan Gränitz if (Error Err = checkOpcode(G, R, Kind)) 601b86420c6SStefan Gränitz return Err; 602b86420c6SStefan Gränitz 6035c1d160cSStefan Gränitz uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 6045c1d160cSStefan Gränitz int64_t Addend = E.getAddend(); 6055c1d160cSStefan Gränitz Symbol &TargetSymbol = E.getTarget(); 6065c1d160cSStefan Gränitz uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 6075c1d160cSStefan Gränitz 6085c1d160cSStefan Gränitz switch (Kind) { 6095c1d160cSStefan Gränitz case Thumb_Jump24: { 6109c017a99SEymen Ünay if (!hasTargetFlags(TargetSymbol, ThumbSymbol)) 6115c1d160cSStefan Gränitz return make_error<JITLinkError>("Branch relocation needs interworking " 6125c1d160cSStefan Gränitz "stub when bridging to ARM: " + 6135c1d160cSStefan Gränitz StringRef(G.getEdgeKindName(Kind))); 6145c1d160cSStefan Gränitz 6155c1d160cSStefan Gränitz int64_t Value = TargetAddress - FixupAddress + Addend; 6165c1d160cSStefan Gränitz if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 6175c1d160cSStefan Gränitz if (!isInt<25>(Value)) 6185c1d160cSStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 6195c1d160cSStefan Gränitz writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 6205c1d160cSStefan Gränitz } else { 6215c1d160cSStefan Gränitz if (!isInt<22>(Value)) 6225c1d160cSStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 6235c1d160cSStefan Gränitz writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value)); 6245c1d160cSStefan Gränitz } 6255c1d160cSStefan Gränitz 6265c1d160cSStefan Gränitz return Error::success(); 6275c1d160cSStefan Gränitz } 6285c1d160cSStefan Gränitz 6295c1d160cSStefan Gränitz case Thumb_Call: { 6305c1d160cSStefan Gränitz int64_t Value = TargetAddress - FixupAddress + Addend; 6315c1d160cSStefan Gränitz 6325c1d160cSStefan Gränitz // The call instruction itself is Thumb. The call destination can either be 6335c1d160cSStefan Gränitz // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm. 6349c017a99SEymen Ünay bool TargetIsArm = !hasTargetFlags(TargetSymbol, ThumbSymbol); 6355c1d160cSStefan Gränitz bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0; 6365c1d160cSStefan Gränitz if (TargetIsArm != InstrIsBlx) { 6375c1d160cSStefan Gränitz if (LLVM_LIKELY(TargetIsArm)) { 6381025189eSStefan Gränitz // Change opcode BL -> BLX and fix range value: account for 4-byte 6395c1d160cSStefan Gränitz // aligned destination while instruction may only be 2-byte aligned 6405c1d160cSStefan Gränitz R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 6415c1d160cSStefan Gränitz R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH; 6425c1d160cSStefan Gränitz Value = alignTo(Value, 4); 6435c1d160cSStefan Gränitz } else { 6441025189eSStefan Gränitz // Change opcode BLX -> BL 6455c1d160cSStefan Gränitz R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 6465c1d160cSStefan Gränitz } 6475c1d160cSStefan Gränitz } 6485c1d160cSStefan Gränitz 6495c1d160cSStefan Gränitz if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 6505c1d160cSStefan Gränitz if (!isInt<25>(Value)) 6515c1d160cSStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 6525c1d160cSStefan Gränitz writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 6535c1d160cSStefan Gränitz } else { 6545c1d160cSStefan Gränitz if (!isInt<22>(Value)) 6555c1d160cSStefan Gränitz return makeTargetOutOfRangeError(G, B, E); 6565c1d160cSStefan Gränitz writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value)); 6575c1d160cSStefan Gränitz } 6585c1d160cSStefan Gränitz 6595c1d160cSStefan Gränitz assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) || 6605c1d160cSStefan Gränitz (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) && 6615c1d160cSStefan Gränitz "Opcode BLX implies H bit is clear (avoid UB in BLX T2)"); 6625c1d160cSStefan Gränitz return Error::success(); 6635c1d160cSStefan Gränitz } 6645c1d160cSStefan Gränitz 6655c1d160cSStefan Gränitz case Thumb_MovwAbsNC: { 6665c1d160cSStefan Gränitz uint16_t Value = (TargetAddress + Addend) & 0xffff; 6675c1d160cSStefan Gränitz writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value)); 6685c1d160cSStefan Gränitz return Error::success(); 6695c1d160cSStefan Gränitz } 6705c1d160cSStefan Gränitz case Thumb_MovtAbs: { 6715c1d160cSStefan Gränitz uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 6725c1d160cSStefan Gränitz writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value)); 6735c1d160cSStefan Gränitz return Error::success(); 6745c1d160cSStefan Gränitz } 67587081f1cSEymen Ünay case Thumb_MovwPrelNC: { 67687081f1cSEymen Ünay uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff); 677b86420c6SStefan Gränitz writeImmediate<Thumb_MovwPrelNC>(R, encodeImmMovtT1MovwT3(Value)); 67887081f1cSEymen Ünay return Error::success(); 67987081f1cSEymen Ünay } 68087081f1cSEymen Ünay case Thumb_MovtPrel: { 68187081f1cSEymen Ünay uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff); 682b86420c6SStefan Gränitz writeImmediate<Thumb_MovtPrel>(R, encodeImmMovtT1MovwT3(Value)); 68387081f1cSEymen Ünay return Error::success(); 68487081f1cSEymen Ünay } 6855c1d160cSStefan Gränitz 6865c1d160cSStefan Gränitz default: 6875c1d160cSStefan Gränitz return make_error<JITLinkError>( 6885c1d160cSStefan Gränitz "In graph " + G.getName() + ", section " + B.getSection().getName() + 6895c1d160cSStefan Gränitz " encountered unfixable aarch32 edge kind " + 6905c1d160cSStefan Gränitz G.getEdgeKindName(E.getKind())); 6915c1d160cSStefan Gränitz } 6925c1d160cSStefan Gränitz } 6935c1d160cSStefan Gränitz 694c4fc563bSStefan Gränitz const uint8_t GOTEntryInit[] = { 695c4fc563bSStefan Gränitz 0x00, 696c4fc563bSStefan Gränitz 0x00, 697c4fc563bSStefan Gränitz 0x00, 698c4fc563bSStefan Gränitz 0x00, 699c4fc563bSStefan Gränitz }; 700c4fc563bSStefan Gränitz 701c4fc563bSStefan Gränitz /// Create a new node in the link-graph for the given pointer value. 702c4fc563bSStefan Gränitz template <size_t Size> 703c4fc563bSStefan Gränitz static Block &allocPointer(LinkGraph &G, Section &S, 704c4fc563bSStefan Gränitz const uint8_t (&Content)[Size]) { 705c4fc563bSStefan Gränitz static_assert(Size == 4, "Pointers are 32-bit"); 706c4fc563bSStefan Gränitz constexpr uint64_t Alignment = 4; 707c4fc563bSStefan Gränitz ArrayRef<char> Init(reinterpret_cast<const char *>(Content), Size); 708c4fc563bSStefan Gränitz return G.createContentBlock(S, Init, orc::ExecutorAddr(), Alignment, 0); 709c4fc563bSStefan Gränitz } 710c4fc563bSStefan Gränitz 711c4fc563bSStefan Gränitz Symbol &GOTBuilder::createEntry(LinkGraph &G, Symbol &Target) { 712c4fc563bSStefan Gränitz if (!GOTSection) 713c4fc563bSStefan Gränitz GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read); 714c4fc563bSStefan Gränitz Block &B = allocPointer(G, *GOTSection, GOTEntryInit); 715c4fc563bSStefan Gränitz constexpr int64_t GOTEntryAddend = 0; 716c4fc563bSStefan Gränitz B.addEdge(Data_Pointer32, 0, Target, GOTEntryAddend); 717c4fc563bSStefan Gränitz return G.addAnonymousSymbol(B, 0, B.getSize(), false, false); 718c4fc563bSStefan Gränitz } 719c4fc563bSStefan Gränitz 720c4fc563bSStefan Gränitz bool GOTBuilder::visitEdge(LinkGraph &G, Block *B, Edge &E) { 721c4fc563bSStefan Gränitz Edge::Kind KindToSet = Edge::Invalid; 722c4fc563bSStefan Gränitz switch (E.getKind()) { 723c4fc563bSStefan Gränitz case aarch32::Data_RequestGOTAndTransformToDelta32: { 724c4fc563bSStefan Gränitz KindToSet = aarch32::Data_Delta32; 725c4fc563bSStefan Gränitz break; 726c4fc563bSStefan Gränitz } 727c4fc563bSStefan Gränitz default: 728c4fc563bSStefan Gränitz return false; 729c4fc563bSStefan Gränitz } 730c4fc563bSStefan Gränitz LLVM_DEBUG(dbgs() << " Transforming " << G.getEdgeKindName(E.getKind()) 731c4fc563bSStefan Gränitz << " edge at " << B->getFixupAddress(E) << " (" 732c4fc563bSStefan Gränitz << B->getAddress() << " + " 733c4fc563bSStefan Gränitz << formatv("{0:x}", E.getOffset()) << ") into " 734c4fc563bSStefan Gränitz << G.getEdgeKindName(KindToSet) << "\n"); 735c4fc563bSStefan Gränitz E.setKind(KindToSet); 736c4fc563bSStefan Gränitz E.setTarget(getEntryForTarget(G, E.getTarget())); 737c4fc563bSStefan Gränitz return true; 738c4fc563bSStefan Gränitz } 739c4fc563bSStefan Gränitz 74055929cd6SStefan Gränitz const uint8_t ArmThumbv5LdrPc[] = { 74155929cd6SStefan Gränitz 0x78, 0x47, // bx pc 74255929cd6SStefan Gränitz 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc 74355929cd6SStefan Gränitz 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 74455929cd6SStefan Gränitz 0x00, 0x00, 0x00, 0x00, // L1: .word S 74555929cd6SStefan Gränitz }; 74655929cd6SStefan Gränitz 747e5ca202eSStefan Gränitz const uint8_t Armv7ABS[] = { 748e5ca202eSStefan Gränitz 0x00, 0xc0, 0x00, 0xe3, // movw r12, #0x0000 ; lower 16-bit 749e5ca202eSStefan Gränitz 0x00, 0xc0, 0x40, 0xe3, // movt r12, #0x0000 ; upper 16-bit 750e5ca202eSStefan Gränitz 0x1c, 0xff, 0x2f, 0xe1 // bx r12 751e5ca202eSStefan Gränitz }; 752e5ca202eSStefan Gränitz 7535c1d160cSStefan Gränitz const uint8_t Thumbv7ABS[] = { 7545c1d160cSStefan Gränitz 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit 7555c1d160cSStefan Gränitz 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit 7565c1d160cSStefan Gränitz 0x60, 0x47 // bx r12 7575c1d160cSStefan Gränitz }; 7585c1d160cSStefan Gränitz 759e5ca202eSStefan Gränitz /// Create a new node in the link-graph for the given stub template. 760e5ca202eSStefan Gränitz template <size_t Size> 761e5ca202eSStefan Gränitz static Block &allocStub(LinkGraph &G, Section &S, const uint8_t (&Code)[Size]) { 7625c1d160cSStefan Gränitz constexpr uint64_t Alignment = 4; 763e5ca202eSStefan Gränitz ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size); 764e5ca202eSStefan Gränitz return G.createContentBlock(S, Template, orc::ExecutorAddr(), Alignment, 0); 765e5ca202eSStefan Gränitz } 766e5ca202eSStefan Gränitz 76755929cd6SStefan Gränitz static Block &createStubPrev7(LinkGraph &G, Section &S, Symbol &Target) { 76855929cd6SStefan Gränitz Block &B = allocStub(G, S, ArmThumbv5LdrPc); 76955929cd6SStefan Gränitz B.addEdge(Data_Pointer32, 8, Target, 0); 77055929cd6SStefan Gränitz return B; 77155929cd6SStefan Gränitz } 77255929cd6SStefan Gränitz 773e5ca202eSStefan Gränitz static Block &createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target) { 774e5ca202eSStefan Gränitz Block &B = allocStub(G, S, Thumbv7ABS); 775e5ca202eSStefan Gränitz B.addEdge(Thumb_MovwAbsNC, 0, Target, 0); 776e5ca202eSStefan Gränitz B.addEdge(Thumb_MovtAbs, 4, Target, 0); 777e5ca202eSStefan Gränitz 778e5ca202eSStefan Gränitz [[maybe_unused]] const char *StubPtr = B.getContent().data(); 779e5ca202eSStefan Gränitz [[maybe_unused]] HalfWords Reg12 = encodeRegMovtT1MovwT3(12); 7805c1d160cSStefan Gränitz assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && 7815c1d160cSStefan Gränitz checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && 7825c1d160cSStefan Gränitz "Linker generated stubs may only corrupt register r12 (IP)"); 783e5ca202eSStefan Gränitz return B; 784e5ca202eSStefan Gränitz } 785e5ca202eSStefan Gränitz 786e5ca202eSStefan Gränitz static Block &createStubArmv7(LinkGraph &G, Section &S, Symbol &Target) { 787e5ca202eSStefan Gränitz Block &B = allocStub(G, S, Armv7ABS); 788e5ca202eSStefan Gränitz B.addEdge(Arm_MovwAbsNC, 0, Target, 0); 789e5ca202eSStefan Gränitz B.addEdge(Arm_MovtAbs, 4, Target, 0); 790e5ca202eSStefan Gränitz 791e5ca202eSStefan Gränitz [[maybe_unused]] const char *StubPtr = B.getContent().data(); 792e5ca202eSStefan Gränitz [[maybe_unused]] uint32_t Reg12 = encodeRegMovtA1MovwA2(12); 793e5ca202eSStefan Gränitz assert(checkRegister<Arm_MovwAbsNC>(StubPtr, Reg12) && 794e5ca202eSStefan Gränitz checkRegister<Arm_MovtAbs>(StubPtr + 4, Reg12) && 795e5ca202eSStefan Gränitz "Linker generated stubs may only corrupt register r12 (IP)"); 796e5ca202eSStefan Gränitz return B; 797e5ca202eSStefan Gränitz } 798e5ca202eSStefan Gränitz 799e5ca202eSStefan Gränitz static bool needsStub(const Edge &E) { 800e5ca202eSStefan Gränitz Symbol &Target = E.getTarget(); 801e5ca202eSStefan Gränitz 802e5ca202eSStefan Gränitz // Create stubs for external branch targets. 803e5ca202eSStefan Gränitz if (!Target.isDefined()) { 804e5ca202eSStefan Gränitz switch (E.getKind()) { 805e5ca202eSStefan Gränitz case Arm_Call: 806e5ca202eSStefan Gränitz case Arm_Jump24: 807e5ca202eSStefan Gränitz case Thumb_Call: 808e5ca202eSStefan Gränitz case Thumb_Jump24: 809e5ca202eSStefan Gränitz return true; 810e5ca202eSStefan Gränitz default: 811e5ca202eSStefan Gränitz return false; 812e5ca202eSStefan Gränitz } 813e5ca202eSStefan Gränitz } 814e5ca202eSStefan Gränitz 815e5ca202eSStefan Gränitz // For local targets, create interworking stubs if we switch Arm/Thumb with an 816e5ca202eSStefan Gränitz // instruction that cannot switch the instruction set state natively. 817e5ca202eSStefan Gränitz bool TargetIsThumb = Target.getTargetFlags() & ThumbSymbol; 818e5ca202eSStefan Gränitz switch (E.getKind()) { 819e5ca202eSStefan Gränitz case Arm_Jump24: 820e5ca202eSStefan Gränitz return TargetIsThumb; // Branch to Thumb needs interworking stub 821e5ca202eSStefan Gränitz case Thumb_Jump24: 822e5ca202eSStefan Gränitz return !TargetIsThumb; // Branch to Arm needs interworking stub 823e5ca202eSStefan Gränitz default: 824e5ca202eSStefan Gränitz break; 825e5ca202eSStefan Gränitz } 826e5ca202eSStefan Gränitz 827e5ca202eSStefan Gränitz return false; 828e5ca202eSStefan Gränitz } 829e5ca202eSStefan Gränitz 83055929cd6SStefan Gränitz // The ArmThumbv5LdrPc stub has 2 entrypoints: Thumb at offset 0 is taken only 83155929cd6SStefan Gränitz // for Thumb B instructions. Thumb BL is rewritten to BLX and takes the Arm 83255929cd6SStefan Gränitz // entrypoint at offset 4. Arm branches always use that one. 83355929cd6SStefan Gränitz Symbol *StubsManager_prev7::getOrCreateSlotEntrypoint(LinkGraph &G, 83455929cd6SStefan Gränitz StubMapEntry &Slot, 83555929cd6SStefan Gränitz bool Thumb) { 83655929cd6SStefan Gränitz constexpr orc::ExecutorAddrDiff ThumbEntrypointOffset = 0; 83755929cd6SStefan Gränitz constexpr orc::ExecutorAddrDiff ArmEntrypointOffset = 4; 83855929cd6SStefan Gränitz if (Thumb && !Slot.ThumbEntry) { 83955929cd6SStefan Gränitz Slot.ThumbEntry = 84055929cd6SStefan Gränitz &G.addAnonymousSymbol(*Slot.B, ThumbEntrypointOffset, 4, true, false); 84155929cd6SStefan Gränitz Slot.ThumbEntry->setTargetFlags(ThumbSymbol); 84255929cd6SStefan Gränitz } 84355929cd6SStefan Gränitz if (!Thumb && !Slot.ArmEntry) 84455929cd6SStefan Gränitz Slot.ArmEntry = 84555929cd6SStefan Gränitz &G.addAnonymousSymbol(*Slot.B, ArmEntrypointOffset, 8, true, false); 84655929cd6SStefan Gränitz return Thumb ? Slot.ThumbEntry : Slot.ArmEntry; 84755929cd6SStefan Gränitz } 84855929cd6SStefan Gränitz 84955929cd6SStefan Gränitz bool StubsManager_prev7::visitEdge(LinkGraph &G, Block *B, Edge &E) { 85055929cd6SStefan Gränitz if (!needsStub(E)) 85155929cd6SStefan Gränitz return false; 85255929cd6SStefan Gränitz 85355929cd6SStefan Gränitz Symbol &Target = E.getTarget(); 85455929cd6SStefan Gränitz assert(Target.hasName() && "Edge cannot point to anonymous target"); 855*2ccf7ed2SJared Wyles auto [Slot, NewStub] = getStubMapSlot(*Target.getName()); 85655929cd6SStefan Gränitz 85755929cd6SStefan Gränitz if (NewStub) { 85855929cd6SStefan Gränitz if (!StubsSection) 85955929cd6SStefan Gränitz StubsSection = &G.createSection(getSectionName(), 86055929cd6SStefan Gränitz orc::MemProt::Read | orc::MemProt::Exec); 86155929cd6SStefan Gränitz LLVM_DEBUG({ 86255929cd6SStefan Gränitz dbgs() << " Created stub entry for " << Target.getName() << " in " 86355929cd6SStefan Gränitz << StubsSection->getName() << "\n"; 86455929cd6SStefan Gränitz }); 86555929cd6SStefan Gränitz Slot->B = &createStubPrev7(G, *StubsSection, Target); 86655929cd6SStefan Gränitz } 86755929cd6SStefan Gränitz 86855929cd6SStefan Gränitz // The ArmThumbv5LdrPc stub has 2 entrypoints: Thumb at offset 0 is taken only 86955929cd6SStefan Gränitz // for Thumb B instructions. Thumb BL is rewritten to BLX and takes the Arm 87055929cd6SStefan Gränitz // entrypoint at offset 4. Arm branches always use that one. 87155929cd6SStefan Gränitz bool UseThumb = E.getKind() == Thumb_Jump24; 87255929cd6SStefan Gränitz Symbol *StubEntrypoint = getOrCreateSlotEntrypoint(G, *Slot, UseThumb); 87355929cd6SStefan Gränitz 87455929cd6SStefan Gränitz LLVM_DEBUG({ 87555929cd6SStefan Gränitz dbgs() << " Using " << (UseThumb ? "Thumb" : "Arm") << " entrypoint " 87655929cd6SStefan Gränitz << *StubEntrypoint << " in " 87755929cd6SStefan Gränitz << StubEntrypoint->getBlock().getSection().getName() << "\n"; 87855929cd6SStefan Gränitz }); 87955929cd6SStefan Gränitz 88055929cd6SStefan Gränitz E.setTarget(*StubEntrypoint); 88155929cd6SStefan Gränitz return true; 88255929cd6SStefan Gränitz } 88355929cd6SStefan Gränitz 884e5ca202eSStefan Gränitz bool StubsManager_v7::visitEdge(LinkGraph &G, Block *B, Edge &E) { 885e5ca202eSStefan Gränitz if (!needsStub(E)) 886e5ca202eSStefan Gränitz return false; 887e5ca202eSStefan Gränitz 888e5ca202eSStefan Gränitz // Stub Arm/Thumb follows instruction set state at relocation site. 889e5ca202eSStefan Gränitz // TODO: We may reduce them at relaxation time and reuse freed slots. 890e5ca202eSStefan Gränitz bool MakeThumb = (E.getKind() > LastArmRelocation); 891e5ca202eSStefan Gränitz LLVM_DEBUG(dbgs() << " Preparing " << (MakeThumb ? "Thumb" : "Arm") 892e5ca202eSStefan Gränitz << " stub for " << G.getEdgeKindName(E.getKind()) 893e5ca202eSStefan Gränitz << " edge at " << B->getFixupAddress(E) << " (" 894e5ca202eSStefan Gränitz << B->getAddress() << " + " 895e5ca202eSStefan Gränitz << formatv("{0:x}", E.getOffset()) << ")\n"); 896e5ca202eSStefan Gränitz 897e5ca202eSStefan Gränitz Symbol &Target = E.getTarget(); 898e5ca202eSStefan Gränitz assert(Target.hasName() && "Edge cannot point to anonymous target"); 899*2ccf7ed2SJared Wyles Symbol *&StubSymbol = getStubSymbolSlot(*Target.getName(), MakeThumb); 900e5ca202eSStefan Gränitz 901e5ca202eSStefan Gränitz if (!StubSymbol) { 902e5ca202eSStefan Gränitz if (!StubsSection) 903e5ca202eSStefan Gränitz StubsSection = &G.createSection(getSectionName(), 904e5ca202eSStefan Gränitz orc::MemProt::Read | orc::MemProt::Exec); 905e5ca202eSStefan Gränitz Block &B = MakeThumb ? createStubThumbv7(G, *StubsSection, Target) 906e5ca202eSStefan Gränitz : createStubArmv7(G, *StubsSection, Target); 907e5ca202eSStefan Gränitz StubSymbol = &G.addAnonymousSymbol(B, 0, B.getSize(), true, false); 908e5ca202eSStefan Gränitz if (MakeThumb) 909e5ca202eSStefan Gränitz StubSymbol->setTargetFlags(ThumbSymbol); 910e5ca202eSStefan Gränitz 911e5ca202eSStefan Gränitz LLVM_DEBUG({ 912e5ca202eSStefan Gränitz dbgs() << " Created " << (MakeThumb ? "Thumb" : "Arm") << " entry for " 913e5ca202eSStefan Gränitz << Target.getName() << " in " << StubsSection->getName() << ": " 914e5ca202eSStefan Gränitz << *StubSymbol << "\n"; 9155c1d160cSStefan Gränitz }); 916e5ca202eSStefan Gränitz } 917e5ca202eSStefan Gränitz 918e5ca202eSStefan Gränitz assert(MakeThumb == (StubSymbol->getTargetFlags() & ThumbSymbol) && 919e5ca202eSStefan Gränitz "Instruction set states of stub and relocation site should be equal"); 920e5ca202eSStefan Gränitz LLVM_DEBUG({ 921e5ca202eSStefan Gränitz dbgs() << " Using " << (MakeThumb ? "Thumb" : "Arm") << " entry " 922e5ca202eSStefan Gränitz << *StubSymbol << " in " 923e5ca202eSStefan Gränitz << StubSymbol->getBlock().getSection().getName() << "\n"; 924e5ca202eSStefan Gränitz }); 925e5ca202eSStefan Gränitz 926e5ca202eSStefan Gränitz E.setTarget(*StubSymbol); 927e5ca202eSStefan Gränitz return true; 9285c1d160cSStefan Gränitz } 9295c1d160cSStefan Gränitz 9305c1d160cSStefan Gränitz const char *getEdgeKindName(Edge::Kind K) { 9315c1d160cSStefan Gränitz #define KIND_NAME_CASE(K) \ 9325c1d160cSStefan Gränitz case K: \ 9335c1d160cSStefan Gränitz return #K; 9345c1d160cSStefan Gränitz 9355c1d160cSStefan Gränitz switch (K) { 9365c1d160cSStefan Gränitz KIND_NAME_CASE(Data_Delta32) 9373e7cd5eaSEymen Ünay KIND_NAME_CASE(Data_Pointer32) 9389577806bSStefan Gränitz KIND_NAME_CASE(Data_PRel31) 939c4fc563bSStefan Gränitz KIND_NAME_CASE(Data_RequestGOTAndTransformToDelta32) 9405c1d160cSStefan Gränitz KIND_NAME_CASE(Arm_Call) 94162f793ecSEymen Ünay KIND_NAME_CASE(Arm_Jump24) 942e575b7cbSEymen Ünay KIND_NAME_CASE(Arm_MovwAbsNC) 943e575b7cbSEymen Ünay KIND_NAME_CASE(Arm_MovtAbs) 9445c1d160cSStefan Gränitz KIND_NAME_CASE(Thumb_Call) 9455c1d160cSStefan Gränitz KIND_NAME_CASE(Thumb_Jump24) 9465c1d160cSStefan Gränitz KIND_NAME_CASE(Thumb_MovwAbsNC) 9475c1d160cSStefan Gränitz KIND_NAME_CASE(Thumb_MovtAbs) 94887081f1cSEymen Ünay KIND_NAME_CASE(Thumb_MovwPrelNC) 94987081f1cSEymen Ünay KIND_NAME_CASE(Thumb_MovtPrel) 950565470edSStefan Gränitz KIND_NAME_CASE(None) 9515c1d160cSStefan Gränitz default: 9525c1d160cSStefan Gränitz return getGenericEdgeKindName(K); 9535c1d160cSStefan Gränitz } 9545c1d160cSStefan Gränitz #undef KIND_NAME_CASE 9555c1d160cSStefan Gränitz } 9565c1d160cSStefan Gränitz 9575c1d160cSStefan Gränitz const char *getCPUArchName(ARMBuildAttrs::CPUArch K) { 9585c1d160cSStefan Gränitz #define CPUARCH_NAME_CASE(K) \ 9595c1d160cSStefan Gränitz case K: \ 9605c1d160cSStefan Gränitz return #K; 9615c1d160cSStefan Gränitz 9625c1d160cSStefan Gränitz using namespace ARMBuildAttrs; 9635c1d160cSStefan Gränitz switch (K) { 9645c1d160cSStefan Gränitz CPUARCH_NAME_CASE(Pre_v4) 9655c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v4) 9665c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v4T) 9675c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v5T) 9685c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v5TE) 9695c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v5TEJ) 9705c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v6) 9715c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v6KZ) 9725c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v6T2) 9735c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v6K) 9745c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v7) 9755c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v6_M) 9765c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v6S_M) 9775c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v7E_M) 9785c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v8_A) 9795c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v8_R) 9805c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v8_M_Base) 9815c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v8_M_Main) 9825c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v8_1_M_Main) 9835c1d160cSStefan Gränitz CPUARCH_NAME_CASE(v9_A) 9845c1d160cSStefan Gränitz } 9855c1d160cSStefan Gränitz llvm_unreachable("Missing CPUArch in switch?"); 9865c1d160cSStefan Gränitz #undef CPUARCH_NAME_CASE 9875c1d160cSStefan Gränitz } 9885c1d160cSStefan Gränitz 9895c1d160cSStefan Gränitz } // namespace aarch32 9905c1d160cSStefan Gränitz } // namespace jitlink 9915c1d160cSStefan Gränitz } // namespace llvm 992