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" 18*7a6dacacSDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h" 1906c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 2006c3fb27SDimitry Andric #include "llvm/Support/Endian.h" 215f757f3fSDimitry Andric #include "llvm/Support/ManagedStatic.h" 2206c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h" 2306c3fb27SDimitry Andric 2406c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink" 2506c3fb27SDimitry Andric 2606c3fb27SDimitry Andric namespace llvm { 2706c3fb27SDimitry Andric namespace jitlink { 2806c3fb27SDimitry Andric namespace aarch32 { 2906c3fb27SDimitry Andric 305f757f3fSDimitry Andric /// Check whether the given target flags are set for this Symbol. 315f757f3fSDimitry Andric bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags) { 325f757f3fSDimitry Andric return static_cast<TargetFlagsType>(Sym.getTargetFlags()) & Flags; 335f757f3fSDimitry Andric } 345f757f3fSDimitry Andric 3506c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range 3606c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 3706c3fb27SDimitry Andric /// 3806c3fb27SDimitry Andric /// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ] 3906c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 4006c3fb27SDimitry Andric /// 4106c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) { 4206c3fb27SDimitry Andric constexpr uint32_t J1J2 = 0x2800; 4306c3fb27SDimitry Andric uint32_t Imm11H = (Value >> 12) & 0x07ff; 4406c3fb27SDimitry Andric uint32_t Imm11L = (Value >> 1) & 0x07ff; 4506c3fb27SDimitry Andric return HalfWords{Imm11H, Imm11L | J1J2}; 4606c3fb27SDimitry Andric } 4706c3fb27SDimitry Andric 4806c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range 4906c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 5006c3fb27SDimitry Andric /// 5106c3fb27SDimitry Andric /// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0 5206c3fb27SDimitry Andric /// J1^ ^J2 will always be 1 5306c3fb27SDimitry Andric /// 5406c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) { 5506c3fb27SDimitry Andric uint32_t Imm11H = Hi & 0x07ff; 5606c3fb27SDimitry Andric uint32_t Imm11L = Lo & 0x07ff; 5706c3fb27SDimitry Andric return SignExtend64<22>(Imm11H << 12 | Imm11L << 1); 5806c3fb27SDimitry Andric } 5906c3fb27SDimitry Andric 6006c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range 6106c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 6206c3fb27SDimitry Andric /// 6306c3fb27SDimitry Andric /// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ] 6406c3fb27SDimitry Andric /// 6506c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) { 6606c3fb27SDimitry Andric uint32_t S = (Value >> 14) & 0x0400; 6706c3fb27SDimitry Andric uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000); 6806c3fb27SDimitry Andric uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800); 6906c3fb27SDimitry Andric uint32_t Imm10 = (Value >> 12) & 0x03ff; 7006c3fb27SDimitry Andric uint32_t Imm11 = (Value >> 1) & 0x07ff; 7106c3fb27SDimitry Andric return HalfWords{S | Imm10, J1 | J2 | Imm11}; 7206c3fb27SDimitry Andric } 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range 7506c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2). 7606c3fb27SDimitry Andric /// 7706c3fb27SDimitry Andric /// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0 7806c3fb27SDimitry Andric /// 7906c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) { 8006c3fb27SDimitry Andric uint32_t S = Hi & 0x0400; 8106c3fb27SDimitry Andric uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000; 8206c3fb27SDimitry Andric uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000; 8306c3fb27SDimitry Andric uint32_t Imm10 = Hi & 0x03ff; 8406c3fb27SDimitry Andric uint32_t Imm11 = Lo & 0x07ff; 8506c3fb27SDimitry Andric return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1); 8606c3fb27SDimitry Andric } 8706c3fb27SDimitry Andric 885f757f3fSDimitry Andric /// Encode 26-bit immediate value for branch instructions 895f757f3fSDimitry Andric /// (formats B A1, BL A1 and BLX A2). 905f757f3fSDimitry Andric /// 915f757f3fSDimitry Andric /// Imm24:00 -> 00000000:Imm24 925f757f3fSDimitry Andric /// 935f757f3fSDimitry Andric uint32_t encodeImmBA1BlA1BlxA2(int64_t Value) { 945f757f3fSDimitry Andric return (Value >> 2) & 0x00ffffff; 955f757f3fSDimitry Andric } 965f757f3fSDimitry Andric 975f757f3fSDimitry Andric /// Decode 26-bit immediate value for branch instructions 985f757f3fSDimitry Andric /// (formats B A1, BL A1 and BLX A2). 995f757f3fSDimitry Andric /// 1005f757f3fSDimitry Andric /// 00000000:Imm24 -> Imm24:00 1015f757f3fSDimitry Andric /// 1025f757f3fSDimitry Andric int64_t decodeImmBA1BlA1BlxA2(int64_t Value) { 1035f757f3fSDimitry Andric return SignExtend64<26>((Value & 0x00ffffff) << 2); 1045f757f3fSDimitry Andric } 1055f757f3fSDimitry Andric 10606c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and 10706c3fb27SDimitry Andric /// MOVW T3. 10806c3fb27SDimitry Andric /// 10906c3fb27SDimitry Andric /// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] 11006c3fb27SDimitry Andric /// 11106c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) { 11206c3fb27SDimitry Andric uint32_t Imm4 = (Value >> 12) & 0x0f; 11306c3fb27SDimitry Andric uint32_t Imm1 = (Value >> 11) & 0x01; 11406c3fb27SDimitry Andric uint32_t Imm3 = (Value >> 8) & 0x07; 11506c3fb27SDimitry Andric uint32_t Imm8 = Value & 0xff; 11606c3fb27SDimitry Andric return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8}; 11706c3fb27SDimitry Andric } 11806c3fb27SDimitry Andric 11906c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and 12006c3fb27SDimitry Andric /// MOVW T3. 12106c3fb27SDimitry Andric /// 12206c3fb27SDimitry Andric /// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8 12306c3fb27SDimitry Andric /// 12406c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 12506c3fb27SDimitry Andric uint32_t Imm4 = Hi & 0x0f; 12606c3fb27SDimitry Andric uint32_t Imm1 = (Hi >> 10) & 0x01; 12706c3fb27SDimitry Andric uint32_t Imm3 = (Lo >> 12) & 0x07; 12806c3fb27SDimitry Andric uint32_t Imm8 = Lo & 0xff; 12906c3fb27SDimitry Andric uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8; 13006c3fb27SDimitry Andric assert(Imm16 <= 0xffff && "Decoded value out-of-range"); 13106c3fb27SDimitry Andric return Imm16; 13206c3fb27SDimitry Andric } 13306c3fb27SDimitry Andric 13406c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3. 13506c3fb27SDimitry Andric /// 13606c3fb27SDimitry Andric /// Rd4 -> [0000000000000000, 0000:Rd4:00000000] 13706c3fb27SDimitry Andric /// 13806c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) { 13906c3fb27SDimitry Andric uint32_t Rd4 = (Value & 0x0f) << 8; 14006c3fb27SDimitry Andric return HalfWords{0, Rd4}; 14106c3fb27SDimitry Andric } 14206c3fb27SDimitry Andric 14306c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3. 14406c3fb27SDimitry Andric /// 14506c3fb27SDimitry Andric /// [0000000000000000, 0000:Rd4:00000000] -> Rd4 14606c3fb27SDimitry Andric /// 14706c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { 14806c3fb27SDimitry Andric uint32_t Rd4 = (Lo >> 8) & 0x0f; 14906c3fb27SDimitry Andric return Rd4; 15006c3fb27SDimitry Andric } 15106c3fb27SDimitry Andric 1525f757f3fSDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT A1 and 1535f757f3fSDimitry Andric /// MOVW A2. 1545f757f3fSDimitry Andric /// 1555f757f3fSDimitry Andric /// Imm4:Imm12 -> 000000000000:Imm4:0000:Imm12 1565f757f3fSDimitry Andric /// 1575f757f3fSDimitry Andric uint32_t encodeImmMovtA1MovwA2(uint16_t Value) { 1585f757f3fSDimitry Andric uint32_t Imm4 = (Value >> 12) & 0x0f; 1595f757f3fSDimitry Andric uint32_t Imm12 = Value & 0x0fff; 1605f757f3fSDimitry Andric return (Imm4 << 16) | Imm12; 1615f757f3fSDimitry Andric } 1625f757f3fSDimitry Andric 1635f757f3fSDimitry Andric /// Decode 16-bit immediate value for move instruction formats MOVT A1 and 1645f757f3fSDimitry Andric /// MOVW A2. 1655f757f3fSDimitry Andric /// 1665f757f3fSDimitry Andric /// 000000000000:Imm4:0000:Imm12 -> Imm4:Imm12 1675f757f3fSDimitry Andric /// 1685f757f3fSDimitry Andric uint16_t decodeImmMovtA1MovwA2(uint64_t Value) { 1695f757f3fSDimitry Andric uint32_t Imm4 = (Value >> 16) & 0x0f; 1705f757f3fSDimitry Andric uint32_t Imm12 = Value & 0x0fff; 1715f757f3fSDimitry Andric return (Imm4 << 12) | Imm12; 1725f757f3fSDimitry Andric } 1735f757f3fSDimitry Andric 1745f757f3fSDimitry Andric /// Encode register ID for instruction formats MOVT A1 and 1755f757f3fSDimitry Andric /// MOVW A2. 1765f757f3fSDimitry Andric /// 1775f757f3fSDimitry Andric /// Rd4 -> 0000000000000000:Rd4:000000000000 1785f757f3fSDimitry Andric /// 1795f757f3fSDimitry Andric uint32_t encodeRegMovtA1MovwA2(int64_t Value) { 1805f757f3fSDimitry Andric uint32_t Rd4 = (Value & 0x00000f) << 12; 1815f757f3fSDimitry Andric return Rd4; 1825f757f3fSDimitry Andric } 1835f757f3fSDimitry Andric 1845f757f3fSDimitry Andric /// Decode register ID for instruction formats MOVT A1 and 1855f757f3fSDimitry Andric /// MOVW A2. 1865f757f3fSDimitry Andric /// 1875f757f3fSDimitry Andric /// 0000000000000000:Rd4:000000000000 -> Rd4 1885f757f3fSDimitry Andric /// 1895f757f3fSDimitry Andric int64_t decodeRegMovtA1MovwA2(uint64_t Value) { 1905f757f3fSDimitry Andric uint32_t Rd4 = (Value >> 12) & 0x00000f; 1915f757f3fSDimitry Andric return Rd4; 1925f757f3fSDimitry Andric } 1935f757f3fSDimitry Andric 1945f757f3fSDimitry Andric namespace { 1955f757f3fSDimitry Andric 19606c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords. 19706c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi), 19806c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo). 19906c3fb27SDimitry Andric struct WritableThumbRelocation { 20006c3fb27SDimitry Andric /// Create a writable reference to a Thumb32 fixup. 20106c3fb27SDimitry Andric WritableThumbRelocation(char *FixupPtr) 20206c3fb27SDimitry Andric : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)}, 20306c3fb27SDimitry Andric Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {} 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric support::ulittle16_t &Hi; // First halfword 20606c3fb27SDimitry Andric support::ulittle16_t &Lo; // Second halfword 20706c3fb27SDimitry Andric }; 20806c3fb27SDimitry Andric 20906c3fb27SDimitry Andric struct ThumbRelocation { 21006c3fb27SDimitry Andric /// Create a read-only reference to a Thumb32 fixup. 21106c3fb27SDimitry Andric ThumbRelocation(const char *FixupPtr) 21206c3fb27SDimitry Andric : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)}, 21306c3fb27SDimitry Andric Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {} 21406c3fb27SDimitry Andric 21506c3fb27SDimitry Andric /// Create a read-only Thumb32 fixup from a writeable one. 21606c3fb27SDimitry Andric ThumbRelocation(WritableThumbRelocation &Writable) 21706c3fb27SDimitry Andric : Hi{Writable.Hi}, Lo(Writable.Lo) {} 21806c3fb27SDimitry Andric 21906c3fb27SDimitry Andric const support::ulittle16_t &Hi; // First halfword 22006c3fb27SDimitry Andric const support::ulittle16_t &Lo; // Second halfword 22106c3fb27SDimitry Andric }; 22206c3fb27SDimitry Andric 2235f757f3fSDimitry Andric struct WritableArmRelocation { 2245f757f3fSDimitry Andric WritableArmRelocation(char *FixupPtr) 2255f757f3fSDimitry Andric : Wd{*reinterpret_cast<support::ulittle32_t *>(FixupPtr)} {} 2265f757f3fSDimitry Andric 2275f757f3fSDimitry Andric support::ulittle32_t &Wd; 2285f757f3fSDimitry Andric }; 2295f757f3fSDimitry Andric 2305f757f3fSDimitry Andric struct ArmRelocation { 2315f757f3fSDimitry Andric ArmRelocation(const char *FixupPtr) 2325f757f3fSDimitry Andric : Wd{*reinterpret_cast<const support::ulittle32_t *>(FixupPtr)} {} 2335f757f3fSDimitry Andric 2345f757f3fSDimitry Andric ArmRelocation(WritableArmRelocation &Writable) : Wd{Writable.Wd} {} 2355f757f3fSDimitry Andric 2365f757f3fSDimitry Andric const support::ulittle32_t &Wd; 2375f757f3fSDimitry Andric }; 2385f757f3fSDimitry Andric 23906c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, 24006c3fb27SDimitry Andric Edge::Kind Kind) { 24106c3fb27SDimitry Andric return make_error<JITLinkError>( 2425f757f3fSDimitry Andric formatv("Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}", 24306c3fb27SDimitry Andric static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo), 24406c3fb27SDimitry Andric G.getEdgeKindName(Kind))); 24506c3fb27SDimitry Andric } 24606c3fb27SDimitry Andric 2475f757f3fSDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ArmRelocation &R, 2485f757f3fSDimitry Andric Edge::Kind Kind) { 2495f757f3fSDimitry Andric return make_error<JITLinkError>( 2505f757f3fSDimitry Andric formatv("Invalid opcode {0:x8} for relocation: {1}", 2515f757f3fSDimitry Andric static_cast<uint32_t>(R.Wd), G.getEdgeKindName(Kind))); 2525f757f3fSDimitry Andric } 2535f757f3fSDimitry Andric 2545f757f3fSDimitry Andric template <EdgeKind_aarch32 K> constexpr bool isArm() { 2555f757f3fSDimitry Andric return FirstArmRelocation <= K && K <= LastArmRelocation; 2565f757f3fSDimitry Andric } 2575f757f3fSDimitry Andric template <EdgeKind_aarch32 K> constexpr bool isThumb() { 2585f757f3fSDimitry Andric return FirstThumbRelocation <= K && K <= LastThumbRelocation; 2595f757f3fSDimitry Andric } 2605f757f3fSDimitry Andric 2615f757f3fSDimitry Andric template <EdgeKind_aarch32 K> static bool checkOpcodeArm(uint32_t Wd) { 2625f757f3fSDimitry Andric return (Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode; 2635f757f3fSDimitry Andric } 2645f757f3fSDimitry Andric 2655f757f3fSDimitry Andric template <EdgeKind_aarch32 K> 2665f757f3fSDimitry Andric static bool checkOpcodeThumb(uint16_t Hi, uint16_t Lo) { 2675f757f3fSDimitry Andric return (Hi & FixupInfo<K>::OpcodeMask.Hi) == FixupInfo<K>::Opcode.Hi && 2685f757f3fSDimitry Andric (Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.Lo; 2695f757f3fSDimitry Andric } 2705f757f3fSDimitry Andric 2715f757f3fSDimitry Andric class FixupInfoTable { 2725f757f3fSDimitry Andric static constexpr size_t Items = LastRelocation + 1; 2735f757f3fSDimitry Andric 2745f757f3fSDimitry Andric public: 2755f757f3fSDimitry Andric FixupInfoTable() { 2765f757f3fSDimitry Andric populateEntries<FirstArmRelocation, LastArmRelocation>(); 2775f757f3fSDimitry Andric populateEntries<FirstThumbRelocation, LastThumbRelocation>(); 2785f757f3fSDimitry Andric } 2795f757f3fSDimitry Andric 2805f757f3fSDimitry Andric const FixupInfoBase *getEntry(Edge::Kind K) { 2815f757f3fSDimitry Andric assert(K < Data.size() && "Index out of bounds"); 2825f757f3fSDimitry Andric return Data.at(K).get(); 2835f757f3fSDimitry Andric } 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric private: 2865f757f3fSDimitry Andric template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK> void populateEntries() { 2875f757f3fSDimitry Andric assert(K < Data.size() && "Index out of range"); 2885f757f3fSDimitry Andric assert(Data.at(K) == nullptr && "Initialized entries are immutable"); 2895f757f3fSDimitry Andric Data[K] = initEntry<K>(); 2905f757f3fSDimitry Andric if constexpr (K < LastK) { 2915f757f3fSDimitry Andric constexpr auto Next = static_cast<EdgeKind_aarch32>(K + 1); 2925f757f3fSDimitry Andric populateEntries<Next, LastK>(); 2935f757f3fSDimitry Andric } 2945f757f3fSDimitry Andric } 2955f757f3fSDimitry Andric 2965f757f3fSDimitry Andric template <EdgeKind_aarch32 K> 2975f757f3fSDimitry Andric static std::unique_ptr<FixupInfoBase> initEntry() { 2985f757f3fSDimitry Andric auto Entry = std::make_unique<FixupInfo<K>>(); 2995f757f3fSDimitry Andric static_assert(isArm<K>() != isThumb<K>(), "Classes are mutually exclusive"); 3005f757f3fSDimitry Andric if constexpr (isArm<K>()) 3015f757f3fSDimitry Andric Entry->checkOpcode = checkOpcodeArm<K>; 3025f757f3fSDimitry Andric if constexpr (isThumb<K>()) 3035f757f3fSDimitry Andric Entry->checkOpcode = checkOpcodeThumb<K>; 3045f757f3fSDimitry Andric return Entry; 3055f757f3fSDimitry Andric } 3065f757f3fSDimitry Andric 3075f757f3fSDimitry Andric private: 3085f757f3fSDimitry Andric std::array<std::unique_ptr<FixupInfoBase>, Items> Data; 3095f757f3fSDimitry Andric }; 3105f757f3fSDimitry Andric 3115f757f3fSDimitry Andric ManagedStatic<FixupInfoTable> DynFixupInfos; 3125f757f3fSDimitry Andric 3135f757f3fSDimitry Andric } // namespace 3145f757f3fSDimitry Andric 3155f757f3fSDimitry Andric static Error checkOpcode(LinkGraph &G, const ArmRelocation &R, 3165f757f3fSDimitry Andric Edge::Kind Kind) { 3175f757f3fSDimitry Andric assert(Kind >= FirstArmRelocation && Kind <= LastArmRelocation && 3185f757f3fSDimitry Andric "Edge kind must be Arm relocation"); 3195f757f3fSDimitry Andric const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind); 3205f757f3fSDimitry Andric const FixupInfoArm &Info = *static_cast<const FixupInfoArm *>(Entry); 3215f757f3fSDimitry Andric assert(Info.checkOpcode && "Opcode check is mandatory for Arm edges"); 3225f757f3fSDimitry Andric if (!Info.checkOpcode(R.Wd)) 3235f757f3fSDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 3245f757f3fSDimitry Andric 3255f757f3fSDimitry Andric return Error::success(); 3265f757f3fSDimitry Andric } 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric static Error checkOpcode(LinkGraph &G, const ThumbRelocation &R, 3295f757f3fSDimitry Andric Edge::Kind Kind) { 3305f757f3fSDimitry Andric assert(Kind >= FirstThumbRelocation && Kind <= LastThumbRelocation && 3315f757f3fSDimitry Andric "Edge kind must be Thumb relocation"); 3325f757f3fSDimitry Andric const FixupInfoBase *Entry = DynFixupInfos->getEntry(Kind); 3335f757f3fSDimitry Andric const FixupInfoThumb &Info = *static_cast<const FixupInfoThumb *>(Entry); 3345f757f3fSDimitry Andric assert(Info.checkOpcode && "Opcode check is mandatory for Thumb edges"); 3355f757f3fSDimitry Andric if (!Info.checkOpcode(R.Hi, R.Lo)) 3365f757f3fSDimitry Andric return makeUnexpectedOpcodeError(G, R, Kind); 3375f757f3fSDimitry Andric 3385f757f3fSDimitry Andric return Error::success(); 3395f757f3fSDimitry Andric } 3405f757f3fSDimitry Andric 3415f757f3fSDimitry Andric const FixupInfoBase *FixupInfoBase::getDynFixupInfo(Edge::Kind K) { 3425f757f3fSDimitry Andric return DynFixupInfos->getEntry(K); 34306c3fb27SDimitry Andric } 34406c3fb27SDimitry Andric 34506c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 34606c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) { 34706c3fb27SDimitry Andric uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi; 34806c3fb27SDimitry Andric uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo; 34906c3fb27SDimitry Andric return Hi == Reg.Hi && Lo == Reg.Lo; 35006c3fb27SDimitry Andric } 35106c3fb27SDimitry Andric 35206c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 3535f757f3fSDimitry Andric bool checkRegister(const ArmRelocation &R, uint32_t Reg) { 3545f757f3fSDimitry Andric uint32_t Wd = R.Wd & FixupInfo<Kind>::RegMask; 3555f757f3fSDimitry Andric return Wd == Reg; 3565f757f3fSDimitry Andric } 3575f757f3fSDimitry Andric 3585f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind> 3595c16e71dSDimitry Andric void writeRegister(WritableThumbRelocation &R, HalfWords Reg) { 36006c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask; 3615f757f3fSDimitry Andric assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Lo & Reg.Lo) == Reg.Lo && 36206c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 36306c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi; 36406c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo; 36506c3fb27SDimitry Andric } 36606c3fb27SDimitry Andric 36706c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> 3685f757f3fSDimitry Andric void writeRegister(WritableArmRelocation &R, uint32_t Reg) { 3695f757f3fSDimitry Andric static constexpr uint32_t Mask = FixupInfo<Kind>::RegMask; 3705f757f3fSDimitry Andric assert((Mask & Reg) == Reg && "Value bits exceed bit range of given mask"); 3715f757f3fSDimitry Andric R.Wd = (R.Wd & ~Mask) | Reg; 3725f757f3fSDimitry Andric } 3735f757f3fSDimitry Andric 3745f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind> 37506c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) { 37606c3fb27SDimitry Andric static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask; 3775f757f3fSDimitry Andric assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo && 37806c3fb27SDimitry Andric "Value bits exceed bit range of given mask"); 37906c3fb27SDimitry Andric R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi; 38006c3fb27SDimitry Andric R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo; 38106c3fb27SDimitry Andric } 38206c3fb27SDimitry Andric 3835f757f3fSDimitry Andric template <EdgeKind_aarch32 Kind> 3845f757f3fSDimitry Andric void writeImmediate(WritableArmRelocation &R, uint32_t Imm) { 3855f757f3fSDimitry Andric static constexpr uint32_t Mask = FixupInfo<Kind>::ImmMask; 3865f757f3fSDimitry Andric assert((Mask & Imm) == Imm && "Value bits exceed bit range of given mask"); 3875f757f3fSDimitry Andric R.Wd = (R.Wd & ~Mask) | Imm; 3885f757f3fSDimitry Andric } 38906c3fb27SDimitry Andric 3905f757f3fSDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset, 3915f757f3fSDimitry Andric Edge::Kind Kind) { 3925f757f3fSDimitry Andric endianness Endian = G.getEndianness(); 39306c3fb27SDimitry Andric const char *BlockWorkingMem = B.getContent().data(); 3945f757f3fSDimitry Andric const char *FixupPtr = BlockWorkingMem + Offset; 39506c3fb27SDimitry Andric 39606c3fb27SDimitry Andric switch (Kind) { 39706c3fb27SDimitry Andric case Data_Delta32: 39806c3fb27SDimitry Andric case Data_Pointer32: 399*7a6dacacSDimitry Andric case Data_RequestGOTAndTransformToDelta32: 40006c3fb27SDimitry Andric return SignExtend64<32>(support::endian::read32(FixupPtr, Endian)); 401*7a6dacacSDimitry Andric case Data_PRel31: 402*7a6dacacSDimitry Andric return SignExtend64<31>(support::endian::read32(FixupPtr, Endian)); 40306c3fb27SDimitry Andric default: 40406c3fb27SDimitry Andric return make_error<JITLinkError>( 40506c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 40606c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 4075f757f3fSDimitry Andric G.getEdgeKindName(Kind)); 40806c3fb27SDimitry Andric } 40906c3fb27SDimitry Andric } 41006c3fb27SDimitry Andric 4115f757f3fSDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset, 4125f757f3fSDimitry Andric Edge::Kind Kind) { 4135f757f3fSDimitry Andric ArmRelocation R(B.getContent().data() + Offset); 4145f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 4155f757f3fSDimitry Andric return std::move(Err); 41606c3fb27SDimitry Andric 41706c3fb27SDimitry Andric switch (Kind) { 41806c3fb27SDimitry Andric case Arm_Call: 4195f757f3fSDimitry Andric case Arm_Jump24: 4205f757f3fSDimitry Andric return decodeImmBA1BlA1BlxA2(R.Wd); 4215f757f3fSDimitry Andric 4225f757f3fSDimitry Andric case Arm_MovtAbs: 4235f757f3fSDimitry Andric case Arm_MovwAbsNC: 4245f757f3fSDimitry Andric return decodeImmMovtA1MovwA2(R.Wd); 4255f757f3fSDimitry Andric 42606c3fb27SDimitry Andric default: 42706c3fb27SDimitry Andric return make_error<JITLinkError>( 42806c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 42906c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 4305f757f3fSDimitry Andric G.getEdgeKindName(Kind)); 43106c3fb27SDimitry Andric } 43206c3fb27SDimitry Andric } 43306c3fb27SDimitry Andric 4345f757f3fSDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset, 4355f757f3fSDimitry Andric Edge::Kind Kind, const ArmConfig &ArmCfg) { 4365f757f3fSDimitry Andric ThumbRelocation R(B.getContent().data() + Offset); 4375f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 4385f757f3fSDimitry Andric return std::move(Err); 43906c3fb27SDimitry Andric 44006c3fb27SDimitry Andric switch (Kind) { 44106c3fb27SDimitry Andric case Thumb_Call: 44206c3fb27SDimitry Andric case Thumb_Jump24: 44306c3fb27SDimitry Andric return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) 44406c3fb27SDimitry Andric ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) 44506c3fb27SDimitry Andric : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); 44606c3fb27SDimitry Andric 44706c3fb27SDimitry Andric case Thumb_MovwAbsNC: 4485f757f3fSDimitry Andric case Thumb_MovwPrelNC: 44906c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 45006c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 45106c3fb27SDimitry Andric 45206c3fb27SDimitry Andric case Thumb_MovtAbs: 4535f757f3fSDimitry Andric case Thumb_MovtPrel: 45406c3fb27SDimitry Andric // Initial addend is interpreted as a signed value 45506c3fb27SDimitry Andric return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); 45606c3fb27SDimitry Andric 45706c3fb27SDimitry Andric default: 45806c3fb27SDimitry Andric return make_error<JITLinkError>( 45906c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 46006c3fb27SDimitry Andric " can not read implicit addend for aarch32 edge kind " + 4615f757f3fSDimitry Andric G.getEdgeKindName(Kind)); 46206c3fb27SDimitry Andric } 46306c3fb27SDimitry Andric } 46406c3fb27SDimitry Andric 46506c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) { 46606c3fb27SDimitry Andric using namespace support; 46706c3fb27SDimitry Andric 46806c3fb27SDimitry Andric char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 46906c3fb27SDimitry Andric char *FixupPtr = BlockWorkingMem + E.getOffset(); 47006c3fb27SDimitry Andric 47106c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 47206c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 47306c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 47406c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 47506c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 47606c3fb27SDimitry Andric 477*7a6dacacSDimitry Andric // Data relocations have alignment 1, size 4 (except R_ARM_ABS8 and 478*7a6dacacSDimitry Andric // R_ARM_ABS16) and write the full 32-bit result (except R_ARM_PREL31). 47906c3fb27SDimitry Andric switch (Kind) { 48006c3fb27SDimitry Andric case Data_Delta32: { 48106c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 48206c3fb27SDimitry Andric if (!isInt<32>(Value)) 48306c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 484*7a6dacacSDimitry Andric if (LLVM_LIKELY(G.getEndianness() == endianness::little)) 485*7a6dacacSDimitry Andric endian::write32le(FixupPtr, Value); 486*7a6dacacSDimitry Andric else 487*7a6dacacSDimitry Andric endian::write32be(FixupPtr, Value); 48806c3fb27SDimitry Andric return Error::success(); 48906c3fb27SDimitry Andric } 49006c3fb27SDimitry Andric case Data_Pointer32: { 49106c3fb27SDimitry Andric int64_t Value = TargetAddress + Addend; 492*7a6dacacSDimitry Andric if (!isUInt<32>(Value)) 49306c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 494*7a6dacacSDimitry Andric if (LLVM_LIKELY(G.getEndianness() == endianness::little)) 495*7a6dacacSDimitry Andric endian::write32le(FixupPtr, Value); 496*7a6dacacSDimitry Andric else 497*7a6dacacSDimitry Andric endian::write32be(FixupPtr, Value); 49806c3fb27SDimitry Andric return Error::success(); 49906c3fb27SDimitry Andric } 500*7a6dacacSDimitry Andric case Data_PRel31: { 501*7a6dacacSDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 502*7a6dacacSDimitry Andric if (!isInt<31>(Value)) 503*7a6dacacSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 504*7a6dacacSDimitry Andric if (LLVM_LIKELY(G.getEndianness() == endianness::little)) { 505*7a6dacacSDimitry Andric uint32_t MSB = endian::read32le(FixupPtr) & 0x80000000; 506*7a6dacacSDimitry Andric endian::write32le(FixupPtr, MSB | (Value & ~0x80000000)); 507*7a6dacacSDimitry Andric } else { 508*7a6dacacSDimitry Andric uint32_t MSB = endian::read32be(FixupPtr) & 0x80000000; 509*7a6dacacSDimitry Andric endian::write32be(FixupPtr, MSB | (Value & ~0x80000000)); 510*7a6dacacSDimitry Andric } 511*7a6dacacSDimitry Andric return Error::success(); 512*7a6dacacSDimitry Andric } 513*7a6dacacSDimitry Andric case Data_RequestGOTAndTransformToDelta32: 514*7a6dacacSDimitry Andric llvm_unreachable("Should be transformed"); 51506c3fb27SDimitry Andric default: 51606c3fb27SDimitry Andric return make_error<JITLinkError>( 51706c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 51806c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 51906c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 52006c3fb27SDimitry Andric } 52106c3fb27SDimitry Andric } 52206c3fb27SDimitry Andric 52306c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) { 5245f757f3fSDimitry Andric WritableArmRelocation R(B.getAlreadyMutableContent().data() + E.getOffset()); 52506c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 5265f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 5275f757f3fSDimitry Andric return Err; 5285f757f3fSDimitry Andric 5295f757f3fSDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 5305f757f3fSDimitry Andric int64_t Addend = E.getAddend(); 5315f757f3fSDimitry Andric Symbol &TargetSymbol = E.getTarget(); 5325f757f3fSDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 53306c3fb27SDimitry Andric 53406c3fb27SDimitry Andric switch (Kind) { 5355f757f3fSDimitry Andric case Arm_Jump24: { 5365f757f3fSDimitry Andric if (hasTargetFlags(TargetSymbol, ThumbSymbol)) 5375f757f3fSDimitry Andric return make_error<JITLinkError>("Branch relocation needs interworking " 5385f757f3fSDimitry Andric "stub when bridging to Thumb: " + 53906c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 5405f757f3fSDimitry Andric 5415f757f3fSDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 5425f757f3fSDimitry Andric 5435f757f3fSDimitry Andric if (!isInt<26>(Value)) 5445f757f3fSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 5455f757f3fSDimitry Andric writeImmediate<Arm_Jump24>(R, encodeImmBA1BlA1BlxA2(Value)); 5465f757f3fSDimitry Andric 5475f757f3fSDimitry Andric return Error::success(); 5485f757f3fSDimitry Andric } 5495f757f3fSDimitry Andric case Arm_Call: { 5505f757f3fSDimitry Andric if ((R.Wd & FixupInfo<Arm_Call>::CondMask) != 5515f757f3fSDimitry Andric FixupInfo<Arm_Call>::Unconditional) 5525f757f3fSDimitry Andric return make_error<JITLinkError>("Relocation expects an unconditional " 5535f757f3fSDimitry Andric "BL/BLX branch instruction: " + 5545f757f3fSDimitry Andric StringRef(G.getEdgeKindName(Kind))); 5555f757f3fSDimitry Andric 5565f757f3fSDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 5575f757f3fSDimitry Andric 5585f757f3fSDimitry Andric // The call instruction itself is Arm. The call destination can either be 5595f757f3fSDimitry Andric // Thumb or Arm. We use BL to stay in Arm and BLX to change to Thumb. 5605f757f3fSDimitry Andric bool TargetIsThumb = hasTargetFlags(TargetSymbol, ThumbSymbol); 5615f757f3fSDimitry Andric bool InstrIsBlx = (~R.Wd & FixupInfo<Arm_Call>::BitBlx) == 0; 5625f757f3fSDimitry Andric if (TargetIsThumb != InstrIsBlx) { 5635f757f3fSDimitry Andric if (LLVM_LIKELY(TargetIsThumb)) { 5645f757f3fSDimitry Andric // Change opcode BL -> BLX 5655f757f3fSDimitry Andric R.Wd = R.Wd | FixupInfo<Arm_Call>::BitBlx; 5665f757f3fSDimitry Andric R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitH; 5675f757f3fSDimitry Andric } else { 5685f757f3fSDimitry Andric // Change opcode BLX -> BL 5695f757f3fSDimitry Andric R.Wd = R.Wd & ~FixupInfo<Arm_Call>::BitBlx; 5705f757f3fSDimitry Andric } 5715f757f3fSDimitry Andric } 5725f757f3fSDimitry Andric 5735f757f3fSDimitry Andric if (!isInt<26>(Value)) 5745f757f3fSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 5755f757f3fSDimitry Andric writeImmediate<Arm_Call>(R, encodeImmBA1BlA1BlxA2(Value)); 5765f757f3fSDimitry Andric 5775f757f3fSDimitry Andric return Error::success(); 5785f757f3fSDimitry Andric } 5795f757f3fSDimitry Andric case Arm_MovwAbsNC: { 5805f757f3fSDimitry Andric uint16_t Value = (TargetAddress + Addend) & 0xffff; 5815f757f3fSDimitry Andric writeImmediate<Arm_MovwAbsNC>(R, encodeImmMovtA1MovwA2(Value)); 5825f757f3fSDimitry Andric return Error::success(); 5835f757f3fSDimitry Andric } 5845f757f3fSDimitry Andric case Arm_MovtAbs: { 5855f757f3fSDimitry Andric uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 5865f757f3fSDimitry Andric writeImmediate<Arm_MovtAbs>(R, encodeImmMovtA1MovwA2(Value)); 5875f757f3fSDimitry Andric return Error::success(); 5885f757f3fSDimitry Andric } 58906c3fb27SDimitry Andric default: 59006c3fb27SDimitry Andric return make_error<JITLinkError>( 59106c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 59206c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 59306c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 59406c3fb27SDimitry Andric } 59506c3fb27SDimitry Andric } 59606c3fb27SDimitry Andric 59706c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, 59806c3fb27SDimitry Andric const ArmConfig &ArmCfg) { 59906c3fb27SDimitry Andric WritableThumbRelocation R(B.getAlreadyMutableContent().data() + 60006c3fb27SDimitry Andric E.getOffset()); 60106c3fb27SDimitry Andric Edge::Kind Kind = E.getKind(); 6025f757f3fSDimitry Andric if (Error Err = checkOpcode(G, R, Kind)) 6035f757f3fSDimitry Andric return Err; 6045f757f3fSDimitry Andric 60506c3fb27SDimitry Andric uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); 60606c3fb27SDimitry Andric int64_t Addend = E.getAddend(); 60706c3fb27SDimitry Andric Symbol &TargetSymbol = E.getTarget(); 60806c3fb27SDimitry Andric uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); 60906c3fb27SDimitry Andric 61006c3fb27SDimitry Andric switch (Kind) { 61106c3fb27SDimitry Andric case Thumb_Jump24: { 6125f757f3fSDimitry Andric if (!hasTargetFlags(TargetSymbol, ThumbSymbol)) 61306c3fb27SDimitry Andric return make_error<JITLinkError>("Branch relocation needs interworking " 61406c3fb27SDimitry Andric "stub when bridging to ARM: " + 61506c3fb27SDimitry Andric StringRef(G.getEdgeKindName(Kind))); 61606c3fb27SDimitry Andric 61706c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 61806c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 61906c3fb27SDimitry Andric if (!isInt<25>(Value)) 62006c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 62106c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 62206c3fb27SDimitry Andric } else { 62306c3fb27SDimitry Andric if (!isInt<22>(Value)) 62406c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 62506c3fb27SDimitry Andric writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value)); 62606c3fb27SDimitry Andric } 62706c3fb27SDimitry Andric 62806c3fb27SDimitry Andric return Error::success(); 62906c3fb27SDimitry Andric } 63006c3fb27SDimitry Andric 63106c3fb27SDimitry Andric case Thumb_Call: { 63206c3fb27SDimitry Andric int64_t Value = TargetAddress - FixupAddress + Addend; 63306c3fb27SDimitry Andric 63406c3fb27SDimitry Andric // The call instruction itself is Thumb. The call destination can either be 63506c3fb27SDimitry Andric // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm. 6365f757f3fSDimitry Andric bool TargetIsArm = !hasTargetFlags(TargetSymbol, ThumbSymbol); 63706c3fb27SDimitry Andric bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0; 63806c3fb27SDimitry Andric if (TargetIsArm != InstrIsBlx) { 63906c3fb27SDimitry Andric if (LLVM_LIKELY(TargetIsArm)) { 6405f757f3fSDimitry Andric // Change opcode BL -> BLX and fix range value: account for 4-byte 64106c3fb27SDimitry Andric // aligned destination while instruction may only be 2-byte aligned 64206c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 64306c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH; 64406c3fb27SDimitry Andric Value = alignTo(Value, 4); 64506c3fb27SDimitry Andric } else { 6465f757f3fSDimitry Andric // Change opcode BLX -> BL 64706c3fb27SDimitry Andric R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; 64806c3fb27SDimitry Andric } 64906c3fb27SDimitry Andric } 65006c3fb27SDimitry Andric 65106c3fb27SDimitry Andric if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { 65206c3fb27SDimitry Andric if (!isInt<25>(Value)) 65306c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 65406c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); 65506c3fb27SDimitry Andric } else { 65606c3fb27SDimitry Andric if (!isInt<22>(Value)) 65706c3fb27SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 65806c3fb27SDimitry Andric writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value)); 65906c3fb27SDimitry Andric } 66006c3fb27SDimitry Andric 66106c3fb27SDimitry Andric assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) || 66206c3fb27SDimitry Andric (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) && 66306c3fb27SDimitry Andric "Opcode BLX implies H bit is clear (avoid UB in BLX T2)"); 66406c3fb27SDimitry Andric return Error::success(); 66506c3fb27SDimitry Andric } 66606c3fb27SDimitry Andric 66706c3fb27SDimitry Andric case Thumb_MovwAbsNC: { 66806c3fb27SDimitry Andric uint16_t Value = (TargetAddress + Addend) & 0xffff; 66906c3fb27SDimitry Andric writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value)); 67006c3fb27SDimitry Andric return Error::success(); 67106c3fb27SDimitry Andric } 67206c3fb27SDimitry Andric case Thumb_MovtAbs: { 67306c3fb27SDimitry Andric uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; 67406c3fb27SDimitry Andric writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value)); 67506c3fb27SDimitry Andric return Error::success(); 67606c3fb27SDimitry Andric } 6775f757f3fSDimitry Andric case Thumb_MovwPrelNC: { 6785f757f3fSDimitry Andric uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff); 6795f757f3fSDimitry Andric writeImmediate<Thumb_MovwPrelNC>(R, encodeImmMovtT1MovwT3(Value)); 6805f757f3fSDimitry Andric return Error::success(); 6815f757f3fSDimitry Andric } 6825f757f3fSDimitry Andric case Thumb_MovtPrel: { 6835f757f3fSDimitry Andric uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff); 6845f757f3fSDimitry Andric writeImmediate<Thumb_MovtPrel>(R, encodeImmMovtT1MovwT3(Value)); 6855f757f3fSDimitry Andric return Error::success(); 6865f757f3fSDimitry Andric } 68706c3fb27SDimitry Andric 68806c3fb27SDimitry Andric default: 68906c3fb27SDimitry Andric return make_error<JITLinkError>( 69006c3fb27SDimitry Andric "In graph " + G.getName() + ", section " + B.getSection().getName() + 69106c3fb27SDimitry Andric " encountered unfixable aarch32 edge kind " + 69206c3fb27SDimitry Andric G.getEdgeKindName(E.getKind())); 69306c3fb27SDimitry Andric } 69406c3fb27SDimitry Andric } 69506c3fb27SDimitry Andric 696*7a6dacacSDimitry Andric const uint8_t GOTEntryInit[] = { 697*7a6dacacSDimitry Andric 0x00, 698*7a6dacacSDimitry Andric 0x00, 699*7a6dacacSDimitry Andric 0x00, 700*7a6dacacSDimitry Andric 0x00, 701*7a6dacacSDimitry Andric }; 702*7a6dacacSDimitry Andric 703*7a6dacacSDimitry Andric /// Create a new node in the link-graph for the given pointer value. 704*7a6dacacSDimitry Andric template <size_t Size> 705*7a6dacacSDimitry Andric static Block &allocPointer(LinkGraph &G, Section &S, 706*7a6dacacSDimitry Andric const uint8_t (&Content)[Size]) { 707*7a6dacacSDimitry Andric static_assert(Size == 4, "Pointers are 32-bit"); 708*7a6dacacSDimitry Andric constexpr uint64_t Alignment = 4; 709*7a6dacacSDimitry Andric ArrayRef<char> Init(reinterpret_cast<const char *>(Content), Size); 710*7a6dacacSDimitry Andric return G.createContentBlock(S, Init, orc::ExecutorAddr(), Alignment, 0); 711*7a6dacacSDimitry Andric } 712*7a6dacacSDimitry Andric 713*7a6dacacSDimitry Andric Symbol &GOTBuilder::createEntry(LinkGraph &G, Symbol &Target) { 714*7a6dacacSDimitry Andric if (!GOTSection) 715*7a6dacacSDimitry Andric GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read); 716*7a6dacacSDimitry Andric Block &B = allocPointer(G, *GOTSection, GOTEntryInit); 717*7a6dacacSDimitry Andric constexpr int64_t GOTEntryAddend = 0; 718*7a6dacacSDimitry Andric B.addEdge(Data_Pointer32, 0, Target, GOTEntryAddend); 719*7a6dacacSDimitry Andric return G.addAnonymousSymbol(B, 0, B.getSize(), false, false); 720*7a6dacacSDimitry Andric } 721*7a6dacacSDimitry Andric 722*7a6dacacSDimitry Andric bool GOTBuilder::visitEdge(LinkGraph &G, Block *B, Edge &E) { 723*7a6dacacSDimitry Andric Edge::Kind KindToSet = Edge::Invalid; 724*7a6dacacSDimitry Andric switch (E.getKind()) { 725*7a6dacacSDimitry Andric case aarch32::Data_RequestGOTAndTransformToDelta32: { 726*7a6dacacSDimitry Andric KindToSet = aarch32::Data_Delta32; 727*7a6dacacSDimitry Andric break; 728*7a6dacacSDimitry Andric } 729*7a6dacacSDimitry Andric default: 730*7a6dacacSDimitry Andric return false; 731*7a6dacacSDimitry Andric } 732*7a6dacacSDimitry Andric LLVM_DEBUG(dbgs() << " Transforming " << G.getEdgeKindName(E.getKind()) 733*7a6dacacSDimitry Andric << " edge at " << B->getFixupAddress(E) << " (" 734*7a6dacacSDimitry Andric << B->getAddress() << " + " 735*7a6dacacSDimitry Andric << formatv("{0:x}", E.getOffset()) << ") into " 736*7a6dacacSDimitry Andric << G.getEdgeKindName(KindToSet) << "\n"); 737*7a6dacacSDimitry Andric E.setKind(KindToSet); 738*7a6dacacSDimitry Andric E.setTarget(getEntryForTarget(G, E.getTarget())); 739*7a6dacacSDimitry Andric return true; 740*7a6dacacSDimitry Andric } 741*7a6dacacSDimitry Andric 742*7a6dacacSDimitry Andric const uint8_t ArmThumbv5LdrPc[] = { 743*7a6dacacSDimitry Andric 0x78, 0x47, // bx pc 744*7a6dacacSDimitry Andric 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc 745*7a6dacacSDimitry Andric 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 746*7a6dacacSDimitry Andric 0x00, 0x00, 0x00, 0x00, // L1: .word S 747*7a6dacacSDimitry Andric }; 748*7a6dacacSDimitry Andric 749*7a6dacacSDimitry Andric const uint8_t Armv7ABS[] = { 750*7a6dacacSDimitry Andric 0x00, 0xc0, 0x00, 0xe3, // movw r12, #0x0000 ; lower 16-bit 751*7a6dacacSDimitry Andric 0x00, 0xc0, 0x40, 0xe3, // movt r12, #0x0000 ; upper 16-bit 752*7a6dacacSDimitry Andric 0x1c, 0xff, 0x2f, 0xe1 // bx r12 753*7a6dacacSDimitry Andric }; 754*7a6dacacSDimitry Andric 75506c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = { 75606c3fb27SDimitry Andric 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit 75706c3fb27SDimitry Andric 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit 75806c3fb27SDimitry Andric 0x60, 0x47 // bx r12 75906c3fb27SDimitry Andric }; 76006c3fb27SDimitry Andric 761*7a6dacacSDimitry Andric /// Create a new node in the link-graph for the given stub template. 762*7a6dacacSDimitry Andric template <size_t Size> 763*7a6dacacSDimitry Andric static Block &allocStub(LinkGraph &G, Section &S, const uint8_t (&Code)[Size]) { 76406c3fb27SDimitry Andric constexpr uint64_t Alignment = 4; 765*7a6dacacSDimitry Andric ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size); 766*7a6dacacSDimitry Andric return G.createContentBlock(S, Template, orc::ExecutorAddr(), Alignment, 0); 767*7a6dacacSDimitry Andric } 768*7a6dacacSDimitry Andric 769*7a6dacacSDimitry Andric static Block &createStubPrev7(LinkGraph &G, Section &S, Symbol &Target) { 770*7a6dacacSDimitry Andric Block &B = allocStub(G, S, ArmThumbv5LdrPc); 771*7a6dacacSDimitry Andric B.addEdge(Data_Pointer32, 8, Target, 0); 772*7a6dacacSDimitry Andric return B; 773*7a6dacacSDimitry Andric } 774*7a6dacacSDimitry Andric 775*7a6dacacSDimitry Andric static Block &createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target) { 776*7a6dacacSDimitry Andric Block &B = allocStub(G, S, Thumbv7ABS); 777*7a6dacacSDimitry Andric B.addEdge(Thumb_MovwAbsNC, 0, Target, 0); 778*7a6dacacSDimitry Andric B.addEdge(Thumb_MovtAbs, 4, Target, 0); 779*7a6dacacSDimitry Andric 780*7a6dacacSDimitry Andric [[maybe_unused]] const char *StubPtr = B.getContent().data(); 781*7a6dacacSDimitry Andric [[maybe_unused]] HalfWords Reg12 = encodeRegMovtT1MovwT3(12); 78206c3fb27SDimitry Andric assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && 78306c3fb27SDimitry Andric checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && 78406c3fb27SDimitry Andric "Linker generated stubs may only corrupt register r12 (IP)"); 785*7a6dacacSDimitry Andric return B; 786*7a6dacacSDimitry Andric } 787*7a6dacacSDimitry Andric 788*7a6dacacSDimitry Andric static Block &createStubArmv7(LinkGraph &G, Section &S, Symbol &Target) { 789*7a6dacacSDimitry Andric Block &B = allocStub(G, S, Armv7ABS); 790*7a6dacacSDimitry Andric B.addEdge(Arm_MovwAbsNC, 0, Target, 0); 791*7a6dacacSDimitry Andric B.addEdge(Arm_MovtAbs, 4, Target, 0); 792*7a6dacacSDimitry Andric 793*7a6dacacSDimitry Andric [[maybe_unused]] const char *StubPtr = B.getContent().data(); 794*7a6dacacSDimitry Andric [[maybe_unused]] uint32_t Reg12 = encodeRegMovtA1MovwA2(12); 795*7a6dacacSDimitry Andric assert(checkRegister<Arm_MovwAbsNC>(StubPtr, Reg12) && 796*7a6dacacSDimitry Andric checkRegister<Arm_MovtAbs>(StubPtr + 4, Reg12) && 797*7a6dacacSDimitry Andric "Linker generated stubs may only corrupt register r12 (IP)"); 798*7a6dacacSDimitry Andric return B; 799*7a6dacacSDimitry Andric } 800*7a6dacacSDimitry Andric 801*7a6dacacSDimitry Andric static bool needsStub(const Edge &E) { 802*7a6dacacSDimitry Andric Symbol &Target = E.getTarget(); 803*7a6dacacSDimitry Andric 804*7a6dacacSDimitry Andric // Create stubs for external branch targets. 805*7a6dacacSDimitry Andric if (!Target.isDefined()) { 806*7a6dacacSDimitry Andric switch (E.getKind()) { 807*7a6dacacSDimitry Andric case Arm_Call: 808*7a6dacacSDimitry Andric case Arm_Jump24: 809*7a6dacacSDimitry Andric case Thumb_Call: 810*7a6dacacSDimitry Andric case Thumb_Jump24: 811*7a6dacacSDimitry Andric return true; 812*7a6dacacSDimitry Andric default: 813*7a6dacacSDimitry Andric return false; 814*7a6dacacSDimitry Andric } 815*7a6dacacSDimitry Andric } 816*7a6dacacSDimitry Andric 817*7a6dacacSDimitry Andric // For local targets, create interworking stubs if we switch Arm/Thumb with an 818*7a6dacacSDimitry Andric // instruction that cannot switch the instruction set state natively. 819*7a6dacacSDimitry Andric bool TargetIsThumb = Target.getTargetFlags() & ThumbSymbol; 820*7a6dacacSDimitry Andric switch (E.getKind()) { 821*7a6dacacSDimitry Andric case Arm_Jump24: 822*7a6dacacSDimitry Andric return TargetIsThumb; // Branch to Thumb needs interworking stub 823*7a6dacacSDimitry Andric case Thumb_Jump24: 824*7a6dacacSDimitry Andric return !TargetIsThumb; // Branch to Arm needs interworking stub 825*7a6dacacSDimitry Andric default: 826*7a6dacacSDimitry Andric break; 827*7a6dacacSDimitry Andric } 828*7a6dacacSDimitry Andric 829*7a6dacacSDimitry Andric return false; 830*7a6dacacSDimitry Andric } 831*7a6dacacSDimitry Andric 832*7a6dacacSDimitry Andric // The ArmThumbv5LdrPc stub has 2 entrypoints: Thumb at offset 0 is taken only 833*7a6dacacSDimitry Andric // for Thumb B instructions. Thumb BL is rewritten to BLX and takes the Arm 834*7a6dacacSDimitry Andric // entrypoint at offset 4. Arm branches always use that one. 835*7a6dacacSDimitry Andric Symbol *StubsManager_prev7::getOrCreateSlotEntrypoint(LinkGraph &G, 836*7a6dacacSDimitry Andric StubMapEntry &Slot, 837*7a6dacacSDimitry Andric bool Thumb) { 838*7a6dacacSDimitry Andric constexpr orc::ExecutorAddrDiff ThumbEntrypointOffset = 0; 839*7a6dacacSDimitry Andric constexpr orc::ExecutorAddrDiff ArmEntrypointOffset = 4; 840*7a6dacacSDimitry Andric if (Thumb && !Slot.ThumbEntry) { 841*7a6dacacSDimitry Andric Slot.ThumbEntry = 842*7a6dacacSDimitry Andric &G.addAnonymousSymbol(*Slot.B, ThumbEntrypointOffset, 4, true, false); 843*7a6dacacSDimitry Andric Slot.ThumbEntry->setTargetFlags(ThumbSymbol); 844*7a6dacacSDimitry Andric } 845*7a6dacacSDimitry Andric if (!Thumb && !Slot.ArmEntry) 846*7a6dacacSDimitry Andric Slot.ArmEntry = 847*7a6dacacSDimitry Andric &G.addAnonymousSymbol(*Slot.B, ArmEntrypointOffset, 8, true, false); 848*7a6dacacSDimitry Andric return Thumb ? Slot.ThumbEntry : Slot.ArmEntry; 849*7a6dacacSDimitry Andric } 850*7a6dacacSDimitry Andric 851*7a6dacacSDimitry Andric bool StubsManager_prev7::visitEdge(LinkGraph &G, Block *B, Edge &E) { 852*7a6dacacSDimitry Andric if (!needsStub(E)) 853*7a6dacacSDimitry Andric return false; 854*7a6dacacSDimitry Andric 855*7a6dacacSDimitry Andric Symbol &Target = E.getTarget(); 856*7a6dacacSDimitry Andric assert(Target.hasName() && "Edge cannot point to anonymous target"); 857*7a6dacacSDimitry Andric auto [Slot, NewStub] = getStubMapSlot(Target.getName()); 858*7a6dacacSDimitry Andric 859*7a6dacacSDimitry Andric if (NewStub) { 860*7a6dacacSDimitry Andric if (!StubsSection) 861*7a6dacacSDimitry Andric StubsSection = &G.createSection(getSectionName(), 862*7a6dacacSDimitry Andric orc::MemProt::Read | orc::MemProt::Exec); 863*7a6dacacSDimitry Andric LLVM_DEBUG({ 864*7a6dacacSDimitry Andric dbgs() << " Created stub entry for " << Target.getName() << " in " 865*7a6dacacSDimitry Andric << StubsSection->getName() << "\n"; 86606c3fb27SDimitry Andric }); 867*7a6dacacSDimitry Andric Slot->B = &createStubPrev7(G, *StubsSection, Target); 868*7a6dacacSDimitry Andric } 869*7a6dacacSDimitry Andric 870*7a6dacacSDimitry Andric // The ArmThumbv5LdrPc stub has 2 entrypoints: Thumb at offset 0 is taken only 871*7a6dacacSDimitry Andric // for Thumb B instructions. Thumb BL is rewritten to BLX and takes the Arm 872*7a6dacacSDimitry Andric // entrypoint at offset 4. Arm branches always use that one. 873*7a6dacacSDimitry Andric bool UseThumb = E.getKind() == Thumb_Jump24; 874*7a6dacacSDimitry Andric Symbol *StubEntrypoint = getOrCreateSlotEntrypoint(G, *Slot, UseThumb); 875*7a6dacacSDimitry Andric 876*7a6dacacSDimitry Andric LLVM_DEBUG({ 877*7a6dacacSDimitry Andric dbgs() << " Using " << (UseThumb ? "Thumb" : "Arm") << " entrypoint " 878*7a6dacacSDimitry Andric << *StubEntrypoint << " in " 879*7a6dacacSDimitry Andric << StubEntrypoint->getBlock().getSection().getName() << "\n"; 880*7a6dacacSDimitry Andric }); 881*7a6dacacSDimitry Andric 882*7a6dacacSDimitry Andric E.setTarget(*StubEntrypoint); 883*7a6dacacSDimitry Andric return true; 884*7a6dacacSDimitry Andric } 885*7a6dacacSDimitry Andric 886*7a6dacacSDimitry Andric bool StubsManager_v7::visitEdge(LinkGraph &G, Block *B, Edge &E) { 887*7a6dacacSDimitry Andric if (!needsStub(E)) 888*7a6dacacSDimitry Andric return false; 889*7a6dacacSDimitry Andric 890*7a6dacacSDimitry Andric // Stub Arm/Thumb follows instruction set state at relocation site. 891*7a6dacacSDimitry Andric // TODO: We may reduce them at relaxation time and reuse freed slots. 892*7a6dacacSDimitry Andric bool MakeThumb = (E.getKind() > LastArmRelocation); 893*7a6dacacSDimitry Andric LLVM_DEBUG(dbgs() << " Preparing " << (MakeThumb ? "Thumb" : "Arm") 894*7a6dacacSDimitry Andric << " stub for " << G.getEdgeKindName(E.getKind()) 895*7a6dacacSDimitry Andric << " edge at " << B->getFixupAddress(E) << " (" 896*7a6dacacSDimitry Andric << B->getAddress() << " + " 897*7a6dacacSDimitry Andric << formatv("{0:x}", E.getOffset()) << ")\n"); 898*7a6dacacSDimitry Andric 899*7a6dacacSDimitry Andric Symbol &Target = E.getTarget(); 900*7a6dacacSDimitry Andric assert(Target.hasName() && "Edge cannot point to anonymous target"); 901*7a6dacacSDimitry Andric Symbol *&StubSymbol = getStubSymbolSlot(Target.getName(), MakeThumb); 902*7a6dacacSDimitry Andric 903*7a6dacacSDimitry Andric if (!StubSymbol) { 904*7a6dacacSDimitry Andric if (!StubsSection) 905*7a6dacacSDimitry Andric StubsSection = &G.createSection(getSectionName(), 906*7a6dacacSDimitry Andric orc::MemProt::Read | orc::MemProt::Exec); 907*7a6dacacSDimitry Andric Block &B = MakeThumb ? createStubThumbv7(G, *StubsSection, Target) 908*7a6dacacSDimitry Andric : createStubArmv7(G, *StubsSection, Target); 909*7a6dacacSDimitry Andric StubSymbol = &G.addAnonymousSymbol(B, 0, B.getSize(), true, false); 910*7a6dacacSDimitry Andric if (MakeThumb) 911*7a6dacacSDimitry Andric StubSymbol->setTargetFlags(ThumbSymbol); 912*7a6dacacSDimitry Andric 913*7a6dacacSDimitry Andric LLVM_DEBUG({ 914*7a6dacacSDimitry Andric dbgs() << " Created " << (MakeThumb ? "Thumb" : "Arm") << " entry for " 915*7a6dacacSDimitry Andric << Target.getName() << " in " << StubsSection->getName() << ": " 916*7a6dacacSDimitry Andric << *StubSymbol << "\n"; 917*7a6dacacSDimitry Andric }); 918*7a6dacacSDimitry Andric } 919*7a6dacacSDimitry Andric 920*7a6dacacSDimitry Andric assert(MakeThumb == (StubSymbol->getTargetFlags() & ThumbSymbol) && 921*7a6dacacSDimitry Andric "Instruction set states of stub and relocation site should be equal"); 922*7a6dacacSDimitry Andric LLVM_DEBUG({ 923*7a6dacacSDimitry Andric dbgs() << " Using " << (MakeThumb ? "Thumb" : "Arm") << " entry " 924*7a6dacacSDimitry Andric << *StubSymbol << " in " 925*7a6dacacSDimitry Andric << StubSymbol->getBlock().getSection().getName() << "\n"; 926*7a6dacacSDimitry Andric }); 927*7a6dacacSDimitry Andric 928*7a6dacacSDimitry Andric E.setTarget(*StubSymbol); 929*7a6dacacSDimitry Andric return true; 93006c3fb27SDimitry Andric } 93106c3fb27SDimitry Andric 93206c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) { 93306c3fb27SDimitry Andric #define KIND_NAME_CASE(K) \ 93406c3fb27SDimitry Andric case K: \ 93506c3fb27SDimitry Andric return #K; 93606c3fb27SDimitry Andric 93706c3fb27SDimitry Andric switch (K) { 93806c3fb27SDimitry Andric KIND_NAME_CASE(Data_Delta32) 9395f757f3fSDimitry Andric KIND_NAME_CASE(Data_Pointer32) 940*7a6dacacSDimitry Andric KIND_NAME_CASE(Data_PRel31) 941*7a6dacacSDimitry Andric KIND_NAME_CASE(Data_RequestGOTAndTransformToDelta32) 94206c3fb27SDimitry Andric KIND_NAME_CASE(Arm_Call) 9435f757f3fSDimitry Andric KIND_NAME_CASE(Arm_Jump24) 9445f757f3fSDimitry Andric KIND_NAME_CASE(Arm_MovwAbsNC) 9455f757f3fSDimitry Andric KIND_NAME_CASE(Arm_MovtAbs) 94606c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Call) 94706c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_Jump24) 94806c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovwAbsNC) 94906c3fb27SDimitry Andric KIND_NAME_CASE(Thumb_MovtAbs) 9505f757f3fSDimitry Andric KIND_NAME_CASE(Thumb_MovwPrelNC) 9515f757f3fSDimitry Andric KIND_NAME_CASE(Thumb_MovtPrel) 952*7a6dacacSDimitry Andric KIND_NAME_CASE(None) 95306c3fb27SDimitry Andric default: 95406c3fb27SDimitry Andric return getGenericEdgeKindName(K); 95506c3fb27SDimitry Andric } 95606c3fb27SDimitry Andric #undef KIND_NAME_CASE 95706c3fb27SDimitry Andric } 95806c3fb27SDimitry Andric 95906c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) { 96006c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K) \ 96106c3fb27SDimitry Andric case K: \ 96206c3fb27SDimitry Andric return #K; 96306c3fb27SDimitry Andric 96406c3fb27SDimitry Andric using namespace ARMBuildAttrs; 96506c3fb27SDimitry Andric switch (K) { 96606c3fb27SDimitry Andric CPUARCH_NAME_CASE(Pre_v4) 96706c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4) 96806c3fb27SDimitry Andric CPUARCH_NAME_CASE(v4T) 96906c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5T) 97006c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TE) 97106c3fb27SDimitry Andric CPUARCH_NAME_CASE(v5TEJ) 97206c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6) 97306c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6KZ) 97406c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6T2) 97506c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6K) 97606c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7) 97706c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6_M) 97806c3fb27SDimitry Andric CPUARCH_NAME_CASE(v6S_M) 97906c3fb27SDimitry Andric CPUARCH_NAME_CASE(v7E_M) 98006c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_A) 98106c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_R) 98206c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Base) 98306c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_M_Main) 98406c3fb27SDimitry Andric CPUARCH_NAME_CASE(v8_1_M_Main) 98506c3fb27SDimitry Andric CPUARCH_NAME_CASE(v9_A) 98606c3fb27SDimitry Andric } 98706c3fb27SDimitry Andric llvm_unreachable("Missing CPUArch in switch?"); 98806c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE 98906c3fb27SDimitry Andric } 99006c3fb27SDimitry Andric 99106c3fb27SDimitry Andric } // namespace aarch32 99206c3fb27SDimitry Andric } // namespace jitlink 99306c3fb27SDimitry Andric } // namespace llvm 994