xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
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