xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric //
9*06c3fb27SDimitry Andric // Generic utilities for graphs representing arm/thumb objects.
10*06c3fb27SDimitry Andric //
11*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch32.h"
14*06c3fb27SDimitry Andric 
15*06c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
16*06c3fb27SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
17*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18*06c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
19*06c3fb27SDimitry Andric #include "llvm/Support/Endian.h"
20*06c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h"
21*06c3fb27SDimitry Andric 
22*06c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink"
23*06c3fb27SDimitry Andric 
24*06c3fb27SDimitry Andric namespace llvm {
25*06c3fb27SDimitry Andric namespace jitlink {
26*06c3fb27SDimitry Andric namespace aarch32 {
27*06c3fb27SDimitry Andric 
28*06c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range
29*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
30*06c3fb27SDimitry Andric ///
31*06c3fb27SDimitry Andric ///   00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ]
32*06c3fb27SDimitry Andric ///                                            J1^ ^J2 will always be 1
33*06c3fb27SDimitry Andric ///
34*06c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) {
35*06c3fb27SDimitry Andric   constexpr uint32_t J1J2 = 0x2800;
36*06c3fb27SDimitry Andric   uint32_t Imm11H = (Value >> 12) & 0x07ff;
37*06c3fb27SDimitry Andric   uint32_t Imm11L = (Value >> 1) & 0x07ff;
38*06c3fb27SDimitry Andric   return HalfWords{Imm11H, Imm11L | J1J2};
39*06c3fb27SDimitry Andric }
40*06c3fb27SDimitry Andric 
41*06c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range
42*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
43*06c3fb27SDimitry Andric ///
44*06c3fb27SDimitry Andric ///   [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0
45*06c3fb27SDimitry Andric ///                   J1^ ^J2 will always be 1
46*06c3fb27SDimitry Andric ///
47*06c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) {
48*06c3fb27SDimitry Andric   uint32_t Imm11H = Hi & 0x07ff;
49*06c3fb27SDimitry Andric   uint32_t Imm11L = Lo & 0x07ff;
50*06c3fb27SDimitry Andric   return SignExtend64<22>(Imm11H << 12 | Imm11L << 1);
51*06c3fb27SDimitry Andric }
52*06c3fb27SDimitry Andric 
53*06c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range
54*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
55*06c3fb27SDimitry Andric ///
56*06c3fb27SDimitry Andric ///   S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ]
57*06c3fb27SDimitry Andric ///
58*06c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) {
59*06c3fb27SDimitry Andric   uint32_t S = (Value >> 14) & 0x0400;
60*06c3fb27SDimitry Andric   uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000);
61*06c3fb27SDimitry Andric   uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800);
62*06c3fb27SDimitry Andric   uint32_t Imm10 = (Value >> 12) & 0x03ff;
63*06c3fb27SDimitry Andric   uint32_t Imm11 = (Value >> 1) & 0x07ff;
64*06c3fb27SDimitry Andric   return HalfWords{S | Imm10, J1 | J2 | Imm11};
65*06c3fb27SDimitry Andric }
66*06c3fb27SDimitry Andric 
67*06c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range
68*06c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
69*06c3fb27SDimitry Andric ///
70*06c3fb27SDimitry Andric ///   [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0
71*06c3fb27SDimitry Andric ///
72*06c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) {
73*06c3fb27SDimitry Andric   uint32_t S = Hi & 0x0400;
74*06c3fb27SDimitry Andric   uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000;
75*06c3fb27SDimitry Andric   uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000;
76*06c3fb27SDimitry Andric   uint32_t Imm10 = Hi & 0x03ff;
77*06c3fb27SDimitry Andric   uint32_t Imm11 = Lo & 0x07ff;
78*06c3fb27SDimitry Andric   return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1);
79*06c3fb27SDimitry Andric }
80*06c3fb27SDimitry Andric 
81*06c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and
82*06c3fb27SDimitry Andric /// MOVW T3.
83*06c3fb27SDimitry Andric ///
84*06c3fb27SDimitry Andric ///   Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ]
85*06c3fb27SDimitry Andric ///
86*06c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) {
87*06c3fb27SDimitry Andric   uint32_t Imm4 = (Value >> 12) & 0x0f;
88*06c3fb27SDimitry Andric   uint32_t Imm1 = (Value >> 11) & 0x01;
89*06c3fb27SDimitry Andric   uint32_t Imm3 = (Value >> 8) & 0x07;
90*06c3fb27SDimitry Andric   uint32_t Imm8 = Value & 0xff;
91*06c3fb27SDimitry Andric   return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8};
92*06c3fb27SDimitry Andric }
93*06c3fb27SDimitry Andric 
94*06c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and
95*06c3fb27SDimitry Andric /// MOVW T3.
96*06c3fb27SDimitry Andric ///
97*06c3fb27SDimitry Andric ///   [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8
98*06c3fb27SDimitry Andric ///
99*06c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
100*06c3fb27SDimitry Andric   uint32_t Imm4 = Hi & 0x0f;
101*06c3fb27SDimitry Andric   uint32_t Imm1 = (Hi >> 10) & 0x01;
102*06c3fb27SDimitry Andric   uint32_t Imm3 = (Lo >> 12) & 0x07;
103*06c3fb27SDimitry Andric   uint32_t Imm8 = Lo & 0xff;
104*06c3fb27SDimitry Andric   uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8;
105*06c3fb27SDimitry Andric   assert(Imm16 <= 0xffff && "Decoded value out-of-range");
106*06c3fb27SDimitry Andric   return Imm16;
107*06c3fb27SDimitry Andric }
108*06c3fb27SDimitry Andric 
109*06c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3.
110*06c3fb27SDimitry Andric ///
111*06c3fb27SDimitry Andric ///   Rd4 -> [0000000000000000, 0000:Rd4:00000000]
112*06c3fb27SDimitry Andric ///
113*06c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) {
114*06c3fb27SDimitry Andric   uint32_t Rd4 = (Value & 0x0f) << 8;
115*06c3fb27SDimitry Andric   return HalfWords{0, Rd4};
116*06c3fb27SDimitry Andric }
117*06c3fb27SDimitry Andric 
118*06c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3.
119*06c3fb27SDimitry Andric ///
120*06c3fb27SDimitry Andric ///   [0000000000000000, 0000:Rd4:00000000] -> Rd4
121*06c3fb27SDimitry Andric ///
122*06c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
123*06c3fb27SDimitry Andric   uint32_t Rd4 = (Lo >> 8) & 0x0f;
124*06c3fb27SDimitry Andric   return Rd4;
125*06c3fb27SDimitry Andric }
126*06c3fb27SDimitry Andric 
127*06c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords.
128*06c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi),
129*06c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo).
130*06c3fb27SDimitry Andric struct WritableThumbRelocation {
131*06c3fb27SDimitry Andric   /// Create a writable reference to a Thumb32 fixup.
132*06c3fb27SDimitry Andric   WritableThumbRelocation(char *FixupPtr)
133*06c3fb27SDimitry Andric       : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)},
134*06c3fb27SDimitry Andric         Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {}
135*06c3fb27SDimitry Andric 
136*06c3fb27SDimitry Andric   support::ulittle16_t &Hi; // First halfword
137*06c3fb27SDimitry Andric   support::ulittle16_t &Lo; // Second halfword
138*06c3fb27SDimitry Andric };
139*06c3fb27SDimitry Andric 
140*06c3fb27SDimitry Andric struct ThumbRelocation {
141*06c3fb27SDimitry Andric   /// Create a read-only reference to a Thumb32 fixup.
142*06c3fb27SDimitry Andric   ThumbRelocation(const char *FixupPtr)
143*06c3fb27SDimitry Andric       : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)},
144*06c3fb27SDimitry Andric         Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {}
145*06c3fb27SDimitry Andric 
146*06c3fb27SDimitry Andric   /// Create a read-only Thumb32 fixup from a writeable one.
147*06c3fb27SDimitry Andric   ThumbRelocation(WritableThumbRelocation &Writable)
148*06c3fb27SDimitry Andric       : Hi{Writable.Hi}, Lo(Writable.Lo) {}
149*06c3fb27SDimitry Andric 
150*06c3fb27SDimitry Andric   const support::ulittle16_t &Hi; // First halfword
151*06c3fb27SDimitry Andric   const support::ulittle16_t &Lo; // Second halfword
152*06c3fb27SDimitry Andric };
153*06c3fb27SDimitry Andric 
154*06c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R,
155*06c3fb27SDimitry Andric                                 Edge::Kind Kind) {
156*06c3fb27SDimitry Andric   return make_error<JITLinkError>(
157*06c3fb27SDimitry Andric       formatv("Invalid opcode [ 0x{0:x4}, 0x{1:x4} ] for relocation: {2}",
158*06c3fb27SDimitry Andric               static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo),
159*06c3fb27SDimitry Andric               G.getEdgeKindName(Kind)));
160*06c3fb27SDimitry Andric }
161*06c3fb27SDimitry Andric 
162*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> bool checkOpcode(const ThumbRelocation &R) {
163*06c3fb27SDimitry Andric   uint16_t Hi = R.Hi & FixupInfo<Kind>::OpcodeMask.Hi;
164*06c3fb27SDimitry Andric   uint16_t Lo = R.Lo & FixupInfo<Kind>::OpcodeMask.Lo;
165*06c3fb27SDimitry Andric   return Hi == FixupInfo<Kind>::Opcode.Hi && Lo == FixupInfo<Kind>::Opcode.Lo;
166*06c3fb27SDimitry Andric }
167*06c3fb27SDimitry Andric 
168*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
169*06c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) {
170*06c3fb27SDimitry Andric   uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi;
171*06c3fb27SDimitry Andric   uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo;
172*06c3fb27SDimitry Andric   return Hi == Reg.Hi && Lo == Reg.Lo;
173*06c3fb27SDimitry Andric }
174*06c3fb27SDimitry Andric 
175*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
176*06c3fb27SDimitry Andric bool writeRegister(WritableThumbRelocation &R, HalfWords Reg) {
177*06c3fb27SDimitry Andric   static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask;
178*06c3fb27SDimitry Andric   assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Hi & Reg.Hi) == Reg.Hi &&
179*06c3fb27SDimitry Andric          "Value bits exceed bit range of given mask");
180*06c3fb27SDimitry Andric   R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi;
181*06c3fb27SDimitry Andric   R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo;
182*06c3fb27SDimitry Andric }
183*06c3fb27SDimitry Andric 
184*06c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
185*06c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) {
186*06c3fb27SDimitry Andric   static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask;
187*06c3fb27SDimitry Andric   assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Hi & Imm.Hi) == Imm.Hi &&
188*06c3fb27SDimitry Andric          "Value bits exceed bit range of given mask");
189*06c3fb27SDimitry Andric   R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi;
190*06c3fb27SDimitry Andric   R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo;
191*06c3fb27SDimitry Andric }
192*06c3fb27SDimitry Andric 
193*06c3fb27SDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E) {
194*06c3fb27SDimitry Andric   support::endianness Endian = G.getEndianness();
195*06c3fb27SDimitry Andric   assert(Endian != support::native && "Declare as little or big explicitly");
196*06c3fb27SDimitry Andric 
197*06c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
198*06c3fb27SDimitry Andric   const char *BlockWorkingMem = B.getContent().data();
199*06c3fb27SDimitry Andric   const char *FixupPtr = BlockWorkingMem + E.getOffset();
200*06c3fb27SDimitry Andric 
201*06c3fb27SDimitry Andric   switch (Kind) {
202*06c3fb27SDimitry Andric   case Data_Delta32:
203*06c3fb27SDimitry Andric   case Data_Pointer32:
204*06c3fb27SDimitry Andric     return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
205*06c3fb27SDimitry Andric   default:
206*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
207*06c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
208*06c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
209*06c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
210*06c3fb27SDimitry Andric   }
211*06c3fb27SDimitry Andric }
212*06c3fb27SDimitry Andric 
213*06c3fb27SDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) {
214*06c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
215*06c3fb27SDimitry Andric 
216*06c3fb27SDimitry Andric   switch (Kind) {
217*06c3fb27SDimitry Andric   case Arm_Call:
218*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
219*06c3fb27SDimitry Andric         "Addend extraction for relocation type not yet implemented: " +
220*06c3fb27SDimitry Andric         StringRef(G.getEdgeKindName(Kind)));
221*06c3fb27SDimitry Andric   default:
222*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
223*06c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
224*06c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
225*06c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
226*06c3fb27SDimitry Andric   }
227*06c3fb27SDimitry Andric }
228*06c3fb27SDimitry Andric 
229*06c3fb27SDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E,
230*06c3fb27SDimitry Andric                                   const ArmConfig &ArmCfg) {
231*06c3fb27SDimitry Andric   ThumbRelocation R(B.getContent().data() + E.getOffset());
232*06c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
233*06c3fb27SDimitry Andric 
234*06c3fb27SDimitry Andric   switch (Kind) {
235*06c3fb27SDimitry Andric   case Thumb_Call:
236*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Call>(R))
237*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
238*06c3fb27SDimitry Andric     return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
239*06c3fb27SDimitry Andric                ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
240*06c3fb27SDimitry Andric                : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
241*06c3fb27SDimitry Andric 
242*06c3fb27SDimitry Andric   case Thumb_Jump24:
243*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Jump24>(R))
244*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
245*06c3fb27SDimitry Andric     if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional)
246*06c3fb27SDimitry Andric       return make_error<JITLinkError>("Relocation expects an unconditional "
247*06c3fb27SDimitry Andric                                       "B.W branch instruction: " +
248*06c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
249*06c3fb27SDimitry Andric     return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
250*06c3fb27SDimitry Andric                   ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
251*06c3fb27SDimitry Andric                   : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
252*06c3fb27SDimitry Andric 
253*06c3fb27SDimitry Andric   case Thumb_MovwAbsNC:
254*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovwAbsNC>(R))
255*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
256*06c3fb27SDimitry Andric     // Initial addend is interpreted as a signed value
257*06c3fb27SDimitry Andric     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
258*06c3fb27SDimitry Andric 
259*06c3fb27SDimitry Andric   case Thumb_MovtAbs:
260*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovtAbs>(R))
261*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
262*06c3fb27SDimitry Andric     // Initial addend is interpreted as a signed value
263*06c3fb27SDimitry Andric     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
264*06c3fb27SDimitry Andric 
265*06c3fb27SDimitry Andric   default:
266*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
267*06c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
268*06c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
269*06c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
270*06c3fb27SDimitry Andric   }
271*06c3fb27SDimitry Andric }
272*06c3fb27SDimitry Andric 
273*06c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
274*06c3fb27SDimitry Andric   using namespace support;
275*06c3fb27SDimitry Andric 
276*06c3fb27SDimitry Andric   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
277*06c3fb27SDimitry Andric   char *FixupPtr = BlockWorkingMem + E.getOffset();
278*06c3fb27SDimitry Andric 
279*06c3fb27SDimitry Andric   auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) {
280*06c3fb27SDimitry Andric     assert(Endian != native && "Must be explicit: little or big");
281*06c3fb27SDimitry Andric     assert(isInt<32>(Value) && "Must be in signed 32-bit range");
282*06c3fb27SDimitry Andric     uint32_t Imm = static_cast<int32_t>(Value);
283*06c3fb27SDimitry Andric     if (LLVM_LIKELY(Endian == little))
284*06c3fb27SDimitry Andric       endian::write32<little>(FixupPtr, Imm);
285*06c3fb27SDimitry Andric     else
286*06c3fb27SDimitry Andric       endian::write32<big>(FixupPtr, Imm);
287*06c3fb27SDimitry Andric   };
288*06c3fb27SDimitry Andric 
289*06c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
290*06c3fb27SDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
291*06c3fb27SDimitry Andric   int64_t Addend = E.getAddend();
292*06c3fb27SDimitry Andric   Symbol &TargetSymbol = E.getTarget();
293*06c3fb27SDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
294*06c3fb27SDimitry Andric   assert(!TargetSymbol.hasTargetFlags(ThumbSymbol));
295*06c3fb27SDimitry Andric 
296*06c3fb27SDimitry Andric   // Regular data relocations have size 4, alignment 1 and write the full 32-bit
297*06c3fb27SDimitry Andric   // result to the place; no need for overflow checking. There are three
298*06c3fb27SDimitry Andric   // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31
299*06c3fb27SDimitry Andric   switch (Kind) {
300*06c3fb27SDimitry Andric   case Data_Delta32: {
301*06c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
302*06c3fb27SDimitry Andric     if (!isInt<32>(Value))
303*06c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
304*06c3fb27SDimitry Andric     Write32(Value);
305*06c3fb27SDimitry Andric     return Error::success();
306*06c3fb27SDimitry Andric   }
307*06c3fb27SDimitry Andric   case Data_Pointer32: {
308*06c3fb27SDimitry Andric     int64_t Value = TargetAddress + Addend;
309*06c3fb27SDimitry Andric     if (!isInt<32>(Value))
310*06c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
311*06c3fb27SDimitry Andric     Write32(Value);
312*06c3fb27SDimitry Andric     return Error::success();
313*06c3fb27SDimitry Andric   }
314*06c3fb27SDimitry Andric   default:
315*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
316*06c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
317*06c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
318*06c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
319*06c3fb27SDimitry Andric   }
320*06c3fb27SDimitry Andric }
321*06c3fb27SDimitry Andric 
322*06c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
323*06c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
324*06c3fb27SDimitry Andric 
325*06c3fb27SDimitry Andric   switch (Kind) {
326*06c3fb27SDimitry Andric   case Arm_Call:
327*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
328*06c3fb27SDimitry Andric         "Fix-up for relocation type not yet implemented: " +
329*06c3fb27SDimitry Andric         StringRef(G.getEdgeKindName(Kind)));
330*06c3fb27SDimitry Andric   default:
331*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
332*06c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
333*06c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
334*06c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
335*06c3fb27SDimitry Andric   }
336*06c3fb27SDimitry Andric }
337*06c3fb27SDimitry Andric 
338*06c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
339*06c3fb27SDimitry Andric                       const ArmConfig &ArmCfg) {
340*06c3fb27SDimitry Andric   WritableThumbRelocation R(B.getAlreadyMutableContent().data() +
341*06c3fb27SDimitry Andric                             E.getOffset());
342*06c3fb27SDimitry Andric 
343*06c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
344*06c3fb27SDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
345*06c3fb27SDimitry Andric   int64_t Addend = E.getAddend();
346*06c3fb27SDimitry Andric   Symbol &TargetSymbol = E.getTarget();
347*06c3fb27SDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
348*06c3fb27SDimitry Andric   if (TargetSymbol.hasTargetFlags(ThumbSymbol))
349*06c3fb27SDimitry Andric     TargetAddress |= 0x01;
350*06c3fb27SDimitry Andric 
351*06c3fb27SDimitry Andric   switch (Kind) {
352*06c3fb27SDimitry Andric   case Thumb_Jump24: {
353*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Jump24>(R))
354*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
355*06c3fb27SDimitry Andric     if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional)
356*06c3fb27SDimitry Andric       return make_error<JITLinkError>("Relocation expects an unconditional "
357*06c3fb27SDimitry Andric                                       "B.W branch instruction: " +
358*06c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
359*06c3fb27SDimitry Andric     if (!(TargetSymbol.hasTargetFlags(ThumbSymbol)))
360*06c3fb27SDimitry Andric       return make_error<JITLinkError>("Branch relocation needs interworking "
361*06c3fb27SDimitry Andric                                       "stub when bridging to ARM: " +
362*06c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
363*06c3fb27SDimitry Andric 
364*06c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
365*06c3fb27SDimitry Andric     if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) {
366*06c3fb27SDimitry Andric       if (!isInt<25>(Value))
367*06c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
368*06c3fb27SDimitry Andric       writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value));
369*06c3fb27SDimitry Andric     } else {
370*06c3fb27SDimitry Andric       if (!isInt<22>(Value))
371*06c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
372*06c3fb27SDimitry Andric       writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value));
373*06c3fb27SDimitry Andric     }
374*06c3fb27SDimitry Andric 
375*06c3fb27SDimitry Andric     return Error::success();
376*06c3fb27SDimitry Andric   }
377*06c3fb27SDimitry Andric 
378*06c3fb27SDimitry Andric   case Thumb_Call: {
379*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Call>(R))
380*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
381*06c3fb27SDimitry Andric 
382*06c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
383*06c3fb27SDimitry Andric 
384*06c3fb27SDimitry Andric     // The call instruction itself is Thumb. The call destination can either be
385*06c3fb27SDimitry Andric     // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm.
386*06c3fb27SDimitry Andric     bool TargetIsArm = !TargetSymbol.hasTargetFlags(ThumbSymbol);
387*06c3fb27SDimitry Andric     bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0;
388*06c3fb27SDimitry Andric     if (TargetIsArm != InstrIsBlx) {
389*06c3fb27SDimitry Andric       if (LLVM_LIKELY(TargetIsArm)) {
390*06c3fb27SDimitry Andric         // Change opcode BL -> BLX and fix range value (account for 4-byte
391*06c3fb27SDimitry Andric         // aligned destination while instruction may only be 2-byte aligned
392*06c3fb27SDimitry Andric         // and clear Thumb bit).
393*06c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx;
394*06c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH;
395*06c3fb27SDimitry Andric         Value = alignTo(Value, 4);
396*06c3fb27SDimitry Andric       } else {
397*06c3fb27SDimitry Andric         // Change opcode BLX -> BL and set Thumb bit
398*06c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx;
399*06c3fb27SDimitry Andric         Value |= 0x01;
400*06c3fb27SDimitry Andric       }
401*06c3fb27SDimitry Andric     }
402*06c3fb27SDimitry Andric 
403*06c3fb27SDimitry Andric     if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) {
404*06c3fb27SDimitry Andric       if (!isInt<25>(Value))
405*06c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
406*06c3fb27SDimitry Andric       writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value));
407*06c3fb27SDimitry Andric     } else {
408*06c3fb27SDimitry Andric       if (!isInt<22>(Value))
409*06c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
410*06c3fb27SDimitry Andric       writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value));
411*06c3fb27SDimitry Andric     }
412*06c3fb27SDimitry Andric 
413*06c3fb27SDimitry Andric     assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) ||
414*06c3fb27SDimitry Andric             (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) &&
415*06c3fb27SDimitry Andric            "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
416*06c3fb27SDimitry Andric     return Error::success();
417*06c3fb27SDimitry Andric   }
418*06c3fb27SDimitry Andric 
419*06c3fb27SDimitry Andric   case Thumb_MovwAbsNC: {
420*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovwAbsNC>(R))
421*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
422*06c3fb27SDimitry Andric     uint16_t Value = (TargetAddress + Addend) & 0xffff;
423*06c3fb27SDimitry Andric     writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value));
424*06c3fb27SDimitry Andric     return Error::success();
425*06c3fb27SDimitry Andric   }
426*06c3fb27SDimitry Andric 
427*06c3fb27SDimitry Andric   case Thumb_MovtAbs: {
428*06c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovtAbs>(R))
429*06c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
430*06c3fb27SDimitry Andric     uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
431*06c3fb27SDimitry Andric     writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value));
432*06c3fb27SDimitry Andric     return Error::success();
433*06c3fb27SDimitry Andric   }
434*06c3fb27SDimitry Andric 
435*06c3fb27SDimitry Andric   default:
436*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
437*06c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
438*06c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
439*06c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
440*06c3fb27SDimitry Andric   }
441*06c3fb27SDimitry Andric }
442*06c3fb27SDimitry Andric 
443*06c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = {
444*06c3fb27SDimitry Andric     0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000    ; lower 16-bit
445*06c3fb27SDimitry Andric     0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000    ; upper 16-bit
446*06c3fb27SDimitry Andric     0x60, 0x47              // bx   r12
447*06c3fb27SDimitry Andric };
448*06c3fb27SDimitry Andric 
449*06c3fb27SDimitry Andric template <>
450*06c3fb27SDimitry Andric Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) {
451*06c3fb27SDimitry Andric   constexpr uint64_t Alignment = 4;
452*06c3fb27SDimitry Andric   Block &B = addStub(G, Thumbv7ABS, Alignment);
453*06c3fb27SDimitry Andric   LLVM_DEBUG({
454*06c3fb27SDimitry Andric     const char *StubPtr = B.getContent().data();
455*06c3fb27SDimitry Andric     HalfWords Reg12 = encodeRegMovtT1MovwT3(12);
456*06c3fb27SDimitry Andric     assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
457*06c3fb27SDimitry Andric            checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
458*06c3fb27SDimitry Andric            "Linker generated stubs may only corrupt register r12 (IP)");
459*06c3fb27SDimitry Andric   });
460*06c3fb27SDimitry Andric   B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
461*06c3fb27SDimitry Andric   B.addEdge(Thumb_MovtAbs, 4, Target, 0);
462*06c3fb27SDimitry Andric   Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false);
463*06c3fb27SDimitry Andric   Stub.setTargetFlags(ThumbSymbol);
464*06c3fb27SDimitry Andric   return Stub;
465*06c3fb27SDimitry Andric }
466*06c3fb27SDimitry Andric 
467*06c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) {
468*06c3fb27SDimitry Andric #define KIND_NAME_CASE(K)                                                      \
469*06c3fb27SDimitry Andric   case K:                                                                      \
470*06c3fb27SDimitry Andric     return #K;
471*06c3fb27SDimitry Andric 
472*06c3fb27SDimitry Andric   switch (K) {
473*06c3fb27SDimitry Andric     KIND_NAME_CASE(Data_Delta32)
474*06c3fb27SDimitry Andric     KIND_NAME_CASE(Arm_Call)
475*06c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_Call)
476*06c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_Jump24)
477*06c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_MovwAbsNC)
478*06c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_MovtAbs)
479*06c3fb27SDimitry Andric   default:
480*06c3fb27SDimitry Andric     return getGenericEdgeKindName(K);
481*06c3fb27SDimitry Andric   }
482*06c3fb27SDimitry Andric #undef KIND_NAME_CASE
483*06c3fb27SDimitry Andric }
484*06c3fb27SDimitry Andric 
485*06c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) {
486*06c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K)                                                   \
487*06c3fb27SDimitry Andric   case K:                                                                      \
488*06c3fb27SDimitry Andric     return #K;
489*06c3fb27SDimitry Andric 
490*06c3fb27SDimitry Andric   using namespace ARMBuildAttrs;
491*06c3fb27SDimitry Andric   switch (K) {
492*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(Pre_v4)
493*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v4)
494*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v4T)
495*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5T)
496*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5TE)
497*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5TEJ)
498*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6)
499*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6KZ)
500*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6T2)
501*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6K)
502*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v7)
503*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6_M)
504*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6S_M)
505*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v7E_M)
506*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_A)
507*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_R)
508*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_M_Base)
509*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_M_Main)
510*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_1_M_Main)
511*06c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v9_A)
512*06c3fb27SDimitry Andric   }
513*06c3fb27SDimitry Andric   llvm_unreachable("Missing CPUArch in switch?");
514*06c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE
515*06c3fb27SDimitry Andric }
516*06c3fb27SDimitry Andric 
517*06c3fb27SDimitry Andric } // namespace aarch32
518*06c3fb27SDimitry Andric } // namespace jitlink
519*06c3fb27SDimitry Andric } // namespace llvm
520