1 //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Generic utilities for graphs representing arm/thumb objects.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/aarch32.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/BinaryFormat/ELF.h"
17 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "llvm/Object/ELFObjectFile.h"
19 #include "llvm/Support/Endian.h"
20 #include "llvm/Support/MathExtras.h"
22 #define DEBUG_TYPE "jitlink"
28 /// Check whether the given target flags are set for this Symbol.
29 bool hasTargetFlags(Symbol
&Sym
, TargetFlagsType Flags
) {
30 return static_cast<TargetFlagsType
>(Sym
.getTargetFlags()) & Flags
;
33 /// Encode 22-bit immediate value for branch instructions without J1J2 range
34 /// extension (formats B T4, BL T1 and BLX T2).
36 /// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ]
37 /// J1^ ^J2 will always be 1
39 HalfWords
encodeImmBT4BlT1BlxT2(int64_t Value
) {
40 constexpr uint32_t J1J2
= 0x2800;
41 uint32_t Imm11H
= (Value
>> 12) & 0x07ff;
42 uint32_t Imm11L
= (Value
>> 1) & 0x07ff;
43 return HalfWords
{Imm11H
, Imm11L
| J1J2
};
46 /// Decode 22-bit immediate value for branch instructions without J1J2 range
47 /// extension (formats B T4, BL T1 and BLX T2).
49 /// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0
50 /// J1^ ^J2 will always be 1
52 int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi
, uint32_t Lo
) {
53 uint32_t Imm11H
= Hi
& 0x07ff;
54 uint32_t Imm11L
= Lo
& 0x07ff;
55 return SignExtend64
<22>(Imm11H
<< 12 | Imm11L
<< 1);
58 /// Encode 25-bit immediate value for branch instructions with J1J2 range
59 /// extension (formats B T4, BL T1 and BLX T2).
61 /// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ]
63 HalfWords
encodeImmBT4BlT1BlxT2_J1J2(int64_t Value
) {
64 uint32_t S
= (Value
>> 14) & 0x0400;
65 uint32_t J1
= (((~(Value
>> 10)) ^ (Value
>> 11)) & 0x2000);
66 uint32_t J2
= (((~(Value
>> 11)) ^ (Value
>> 13)) & 0x0800);
67 uint32_t Imm10
= (Value
>> 12) & 0x03ff;
68 uint32_t Imm11
= (Value
>> 1) & 0x07ff;
69 return HalfWords
{S
| Imm10
, J1
| J2
| Imm11
};
72 /// Decode 25-bit immediate value for branch instructions with J1J2 range
73 /// extension (formats B T4, BL T1 and BLX T2).
75 /// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0
77 int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi
, uint32_t Lo
) {
78 uint32_t S
= Hi
& 0x0400;
79 uint32_t I1
= ~((Lo
^ (Hi
<< 3)) << 10) & 0x00800000;
80 uint32_t I2
= ~((Lo
^ (Hi
<< 1)) << 11) & 0x00400000;
81 uint32_t Imm10
= Hi
& 0x03ff;
82 uint32_t Imm11
= Lo
& 0x07ff;
83 return SignExtend64
<25>(S
<< 14 | I1
| I2
| Imm10
<< 12 | Imm11
<< 1);
86 /// Encode 26-bit immediate value for branch instructions
87 /// (formats B A1, BL A1 and BLX A2).
89 /// Imm24:00 -> 00000000:Imm24
91 uint32_t encodeImmBA1BlA1BlxA2(int64_t Value
) {
92 return (Value
>> 2) & 0x00ffffff;
95 /// Decode 26-bit immediate value for branch instructions
96 /// (formats B A1, BL A1 and BLX A2).
98 /// 00000000:Imm24 -> Imm24:00
100 int64_t decodeImmBA1BlA1BlxA2(int64_t Value
) {
101 return SignExtend64
<26>((Value
& 0x00ffffff) << 2);
104 /// Encode 16-bit immediate value for move instruction formats MOVT T1 and
107 /// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ]
109 HalfWords
encodeImmMovtT1MovwT3(uint16_t Value
) {
110 uint32_t Imm4
= (Value
>> 12) & 0x0f;
111 uint32_t Imm1
= (Value
>> 11) & 0x01;
112 uint32_t Imm3
= (Value
>> 8) & 0x07;
113 uint32_t Imm8
= Value
& 0xff;
114 return HalfWords
{Imm1
<< 10 | Imm4
, Imm3
<< 12 | Imm8
};
117 /// Decode 16-bit immediate value from move instruction formats MOVT T1 and
120 /// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8
122 uint16_t decodeImmMovtT1MovwT3(uint32_t Hi
, uint32_t Lo
) {
123 uint32_t Imm4
= Hi
& 0x0f;
124 uint32_t Imm1
= (Hi
>> 10) & 0x01;
125 uint32_t Imm3
= (Lo
>> 12) & 0x07;
126 uint32_t Imm8
= Lo
& 0xff;
127 uint32_t Imm16
= Imm4
<< 12 | Imm1
<< 11 | Imm3
<< 8 | Imm8
;
128 assert(Imm16
<= 0xffff && "Decoded value out-of-range");
132 /// Encode register ID for instruction formats MOVT T1 and MOVW T3.
134 /// Rd4 -> [0000000000000000, 0000:Rd4:00000000]
136 HalfWords
encodeRegMovtT1MovwT3(int64_t Value
) {
137 uint32_t Rd4
= (Value
& 0x0f) << 8;
138 return HalfWords
{0, Rd4
};
141 /// Decode register ID from instruction formats MOVT T1 and MOVW T3.
143 /// [0000000000000000, 0000:Rd4:00000000] -> Rd4
145 int64_t decodeRegMovtT1MovwT3(uint32_t Hi
, uint32_t Lo
) {
146 uint32_t Rd4
= (Lo
>> 8) & 0x0f;
150 /// Encode 16-bit immediate value for move instruction formats MOVT A1 and
153 /// Imm4:Imm12 -> 000000000000:Imm4:0000:Imm12
155 uint32_t encodeImmMovtA1MovwA2(uint16_t Value
) {
156 uint32_t Imm4
= (Value
>> 12) & 0x0f;
157 uint32_t Imm12
= Value
& 0x0fff;
158 return (Imm4
<< 16) | Imm12
;
161 /// Decode 16-bit immediate value for move instruction formats MOVT A1 and
164 /// 000000000000:Imm4:0000:Imm12 -> Imm4:Imm12
166 uint16_t decodeImmMovtA1MovwA2(uint64_t Value
) {
167 uint32_t Imm4
= (Value
>> 16) & 0x0f;
168 uint32_t Imm12
= Value
& 0x0fff;
169 return (Imm4
<< 12) | Imm12
;
172 /// Encode register ID for instruction formats MOVT A1 and
175 /// Rd4 -> 0000000000000000:Rd4:000000000000
177 uint32_t encodeRegMovtA1MovwA2(int64_t Value
) {
178 uint32_t Rd4
= (Value
& 0x00000f) << 12;
182 /// Decode register ID for instruction formats MOVT A1 and
185 /// 0000000000000000:Rd4:000000000000 -> Rd4
187 int64_t decodeRegMovtA1MovwA2(uint64_t Value
) {
188 uint32_t Rd4
= (Value
>> 12) & 0x00000f;
192 /// 32-bit Thumb instructions are stored as two little-endian halfwords.
193 /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi),
194 /// followed by bytes A+3, A+2 in the second halfword (Lo).
195 struct WritableThumbRelocation
{
196 /// Create a writable reference to a Thumb32 fixup.
197 WritableThumbRelocation(char *FixupPtr
)
198 : Hi
{*reinterpret_cast<support::ulittle16_t
*>(FixupPtr
)},
199 Lo
{*reinterpret_cast<support::ulittle16_t
*>(FixupPtr
+ 2)} {}
201 support::ulittle16_t
&Hi
; // First halfword
202 support::ulittle16_t
&Lo
; // Second halfword
205 struct ThumbRelocation
{
206 /// Create a read-only reference to a Thumb32 fixup.
207 ThumbRelocation(const char *FixupPtr
)
208 : Hi
{*reinterpret_cast<const support::ulittle16_t
*>(FixupPtr
)},
209 Lo
{*reinterpret_cast<const support::ulittle16_t
*>(FixupPtr
+ 2)} {}
211 /// Create a read-only Thumb32 fixup from a writeable one.
212 ThumbRelocation(WritableThumbRelocation
&Writable
)
213 : Hi
{Writable
.Hi
}, Lo(Writable
.Lo
) {}
215 const support::ulittle16_t
&Hi
; // First halfword
216 const support::ulittle16_t
&Lo
; // Second halfword
219 struct WritableArmRelocation
{
220 WritableArmRelocation(char *FixupPtr
)
221 : Wd
{*reinterpret_cast<support::ulittle32_t
*>(FixupPtr
)} {}
223 support::ulittle32_t
&Wd
;
226 struct ArmRelocation
{
228 ArmRelocation(const char *FixupPtr
)
229 : Wd
{*reinterpret_cast<const support::ulittle32_t
*>(FixupPtr
)} {}
231 ArmRelocation(WritableArmRelocation
&Writable
) : Wd
{Writable
.Wd
} {}
233 const support::ulittle32_t
&Wd
;
236 Error
makeUnexpectedOpcodeError(const LinkGraph
&G
, const ThumbRelocation
&R
,
238 return make_error
<JITLinkError
>(
239 formatv("Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}",
240 static_cast<uint16_t>(R
.Hi
), static_cast<uint16_t>(R
.Lo
),
241 G
.getEdgeKindName(Kind
)));
244 Error
makeUnexpectedOpcodeError(const LinkGraph
&G
, const ArmRelocation
&R
,
246 return make_error
<JITLinkError
>(
247 formatv("Invalid opcode {0:x8} for relocation: {1}",
248 static_cast<uint32_t>(R
.Wd
), G
.getEdgeKindName(Kind
)));
251 template <EdgeKind_aarch32 Kind
> bool checkOpcode(const ThumbRelocation
&R
) {
252 uint16_t Hi
= R
.Hi
& FixupInfo
<Kind
>::OpcodeMask
.Hi
;
253 uint16_t Lo
= R
.Lo
& FixupInfo
<Kind
>::OpcodeMask
.Lo
;
254 return Hi
== FixupInfo
<Kind
>::Opcode
.Hi
&& Lo
== FixupInfo
<Kind
>::Opcode
.Lo
;
257 template <EdgeKind_aarch32 Kind
> bool checkOpcode(const ArmRelocation
&R
) {
258 uint32_t Wd
= R
.Wd
& FixupInfo
<Kind
>::OpcodeMask
;
259 return Wd
== FixupInfo
<Kind
>::Opcode
;
262 template <EdgeKind_aarch32 Kind
>
263 bool checkRegister(const ThumbRelocation
&R
, HalfWords Reg
) {
264 uint16_t Hi
= R
.Hi
& FixupInfo
<Kind
>::RegMask
.Hi
;
265 uint16_t Lo
= R
.Lo
& FixupInfo
<Kind
>::RegMask
.Lo
;
266 return Hi
== Reg
.Hi
&& Lo
== Reg
.Lo
;
269 template <EdgeKind_aarch32 Kind
>
270 bool checkRegister(const ArmRelocation
&R
, uint32_t Reg
) {
271 uint32_t Wd
= R
.Wd
& FixupInfo
<Kind
>::RegMask
;
275 template <EdgeKind_aarch32 Kind
>
276 void writeRegister(WritableThumbRelocation
&R
, HalfWords Reg
) {
277 static constexpr HalfWords Mask
= FixupInfo
<Kind
>::RegMask
;
278 assert((Mask
.Hi
& Reg
.Hi
) == Reg
.Hi
&& (Mask
.Lo
& Reg
.Lo
) == Reg
.Lo
&&
279 "Value bits exceed bit range of given mask");
280 R
.Hi
= (R
.Hi
& ~Mask
.Hi
) | Reg
.Hi
;
281 R
.Lo
= (R
.Lo
& ~Mask
.Lo
) | Reg
.Lo
;
284 template <EdgeKind_aarch32 Kind
>
285 void writeRegister(WritableArmRelocation
&R
, uint32_t Reg
) {
286 static constexpr uint32_t Mask
= FixupInfo
<Kind
>::RegMask
;
287 assert((Mask
& Reg
) == Reg
&& "Value bits exceed bit range of given mask");
288 R
.Wd
= (R
.Wd
& ~Mask
) | Reg
;
291 template <EdgeKind_aarch32 Kind
>
292 void writeImmediate(WritableThumbRelocation
&R
, HalfWords Imm
) {
293 static constexpr HalfWords Mask
= FixupInfo
<Kind
>::ImmMask
;
294 assert((Mask
.Hi
& Imm
.Hi
) == Imm
.Hi
&& (Mask
.Lo
& Imm
.Lo
) == Imm
.Lo
&&
295 "Value bits exceed bit range of given mask");
296 R
.Hi
= (R
.Hi
& ~Mask
.Hi
) | Imm
.Hi
;
297 R
.Lo
= (R
.Lo
& ~Mask
.Lo
) | Imm
.Lo
;
300 template <EdgeKind_aarch32 Kind
>
301 void writeImmediate(WritableArmRelocation
&R
, uint32_t Imm
) {
302 static constexpr uint32_t Mask
= FixupInfo
<Kind
>::ImmMask
;
303 assert((Mask
& Imm
) == Imm
&& "Value bits exceed bit range of given mask");
304 R
.Wd
= (R
.Wd
& ~Mask
) | Imm
;
307 Expected
<int64_t> readAddendData(LinkGraph
&G
, Block
&B
, const Edge
&E
) {
308 support::endianness Endian
= G
.getEndianness();
309 assert(Endian
!= support::native
&& "Declare as little or big explicitly");
311 Edge::Kind Kind
= E
.getKind();
312 const char *BlockWorkingMem
= B
.getContent().data();
313 const char *FixupPtr
= BlockWorkingMem
+ E
.getOffset();
318 return SignExtend64
<32>(support::endian::read32(FixupPtr
, Endian
));
320 return make_error
<JITLinkError
>(
321 "In graph " + G
.getName() + ", section " + B
.getSection().getName() +
322 " can not read implicit addend for aarch32 edge kind " +
323 G
.getEdgeKindName(E
.getKind()));
327 Expected
<int64_t> readAddendArm(LinkGraph
&G
, Block
&B
, const Edge
&E
) {
328 ArmRelocation
R(B
.getContent().data() + E
.getOffset());
329 Edge::Kind Kind
= E
.getKind();
333 if (!checkOpcode
<Arm_Call
>(R
))
334 return makeUnexpectedOpcodeError(G
, R
, Kind
);
335 return decodeImmBA1BlA1BlxA2(R
.Wd
);
338 if (!checkOpcode
<Arm_Jump24
>(R
))
339 return makeUnexpectedOpcodeError(G
, R
, Kind
);
340 return decodeImmBA1BlA1BlxA2(R
.Wd
);
343 if (!checkOpcode
<Arm_MovwAbsNC
>(R
))
344 return makeUnexpectedOpcodeError(G
, R
, Kind
);
345 return decodeImmMovtA1MovwA2(R
.Wd
);
348 if (!checkOpcode
<Arm_MovtAbs
>(R
))
349 return makeUnexpectedOpcodeError(G
, R
, Kind
);
350 return decodeImmMovtA1MovwA2(R
.Wd
);
353 return make_error
<JITLinkError
>(
354 "In graph " + G
.getName() + ", section " + B
.getSection().getName() +
355 " can not read implicit addend for aarch32 edge kind " +
356 G
.getEdgeKindName(E
.getKind()));
360 Expected
<int64_t> readAddendThumb(LinkGraph
&G
, Block
&B
, const Edge
&E
,
361 const ArmConfig
&ArmCfg
) {
362 ThumbRelocation
R(B
.getContent().data() + E
.getOffset());
363 Edge::Kind Kind
= E
.getKind();
367 if (!checkOpcode
<Thumb_Call
>(R
))
368 return makeUnexpectedOpcodeError(G
, R
, Kind
);
369 return LLVM_LIKELY(ArmCfg
.J1J2BranchEncoding
)
370 ? decodeImmBT4BlT1BlxT2_J1J2(R
.Hi
, R
.Lo
)
371 : decodeImmBT4BlT1BlxT2(R
.Hi
, R
.Lo
);
374 if (!checkOpcode
<Thumb_Jump24
>(R
))
375 return makeUnexpectedOpcodeError(G
, R
, Kind
);
376 return LLVM_LIKELY(ArmCfg
.J1J2BranchEncoding
)
377 ? decodeImmBT4BlT1BlxT2_J1J2(R
.Hi
, R
.Lo
)
378 : decodeImmBT4BlT1BlxT2(R
.Hi
, R
.Lo
);
380 case Thumb_MovwAbsNC
:
381 if (!checkOpcode
<Thumb_MovwAbsNC
>(R
))
382 return makeUnexpectedOpcodeError(G
, R
, Kind
);
383 // Initial addend is interpreted as a signed value
384 return SignExtend64
<16>(decodeImmMovtT1MovwT3(R
.Hi
, R
.Lo
));
387 if (!checkOpcode
<Thumb_MovtAbs
>(R
))
388 return makeUnexpectedOpcodeError(G
, R
, Kind
);
389 // Initial addend is interpreted as a signed value
390 return SignExtend64
<16>(decodeImmMovtT1MovwT3(R
.Hi
, R
.Lo
));
393 return make_error
<JITLinkError
>(
394 "In graph " + G
.getName() + ", section " + B
.getSection().getName() +
395 " can not read implicit addend for aarch32 edge kind " +
396 G
.getEdgeKindName(E
.getKind()));
400 Error
applyFixupData(LinkGraph
&G
, Block
&B
, const Edge
&E
) {
401 using namespace support
;
403 char *BlockWorkingMem
= B
.getAlreadyMutableContent().data();
404 char *FixupPtr
= BlockWorkingMem
+ E
.getOffset();
406 auto Write32
= [FixupPtr
, Endian
= G
.getEndianness()](int64_t Value
) {
407 assert(Endian
!= native
&& "Must be explicit: little or big");
408 assert(isInt
<32>(Value
) && "Must be in signed 32-bit range");
409 uint32_t Imm
= static_cast<int32_t>(Value
);
410 if (LLVM_LIKELY(Endian
== little
))
411 endian::write32
<little
>(FixupPtr
, Imm
);
413 endian::write32
<big
>(FixupPtr
, Imm
);
416 Edge::Kind Kind
= E
.getKind();
417 uint64_t FixupAddress
= (B
.getAddress() + E
.getOffset()).getValue();
418 int64_t Addend
= E
.getAddend();
419 Symbol
&TargetSymbol
= E
.getTarget();
420 uint64_t TargetAddress
= TargetSymbol
.getAddress().getValue();
422 // Regular data relocations have size 4, alignment 1 and write the full 32-bit
423 // result to the place; no need for overflow checking. There are three
424 // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31
427 int64_t Value
= TargetAddress
- FixupAddress
+ Addend
;
428 if (!isInt
<32>(Value
))
429 return makeTargetOutOfRangeError(G
, B
, E
);
431 return Error::success();
433 case Data_Pointer32
: {
434 int64_t Value
= TargetAddress
+ Addend
;
435 if (!isInt
<32>(Value
))
436 return makeTargetOutOfRangeError(G
, B
, E
);
438 return Error::success();
441 return make_error
<JITLinkError
>(
442 "In graph " + G
.getName() + ", section " + B
.getSection().getName() +
443 " encountered unfixable aarch32 edge kind " +
444 G
.getEdgeKindName(E
.getKind()));
448 Error
applyFixupArm(LinkGraph
&G
, Block
&B
, const Edge
&E
) {
449 WritableArmRelocation
R(B
.getAlreadyMutableContent().data() + E
.getOffset());
450 Edge::Kind Kind
= E
.getKind();
451 uint64_t FixupAddress
= (B
.getAddress() + E
.getOffset()).getValue();
452 int64_t Addend
= E
.getAddend();
453 Symbol
&TargetSymbol
= E
.getTarget();
454 uint64_t TargetAddress
= TargetSymbol
.getAddress().getValue();
458 if (!checkOpcode
<Arm_Jump24
>(R
))
459 return makeUnexpectedOpcodeError(G
, R
, Kind
);
460 if (hasTargetFlags(TargetSymbol
, ThumbSymbol
))
461 return make_error
<JITLinkError
>("Branch relocation needs interworking "
462 "stub when bridging to Thumb: " +
463 StringRef(G
.getEdgeKindName(Kind
)));
465 int64_t Value
= TargetAddress
- FixupAddress
+ Addend
;
467 if (!isInt
<26>(Value
))
468 return makeTargetOutOfRangeError(G
, B
, E
);
469 writeImmediate
<Arm_Jump24
>(R
, encodeImmBA1BlA1BlxA2(Value
));
471 return Error::success();
474 if (!checkOpcode
<Arm_Call
>(R
))
475 return makeUnexpectedOpcodeError(G
, R
, Kind
);
476 if ((R
.Wd
& FixupInfo
<Arm_Call
>::CondMask
) !=
477 FixupInfo
<Arm_Call
>::Unconditional
)
478 return make_error
<JITLinkError
>("Relocation expects an unconditional "
479 "BL/BLX branch instruction: " +
480 StringRef(G
.getEdgeKindName(Kind
)));
482 int64_t Value
= TargetAddress
- FixupAddress
+ Addend
;
484 // The call instruction itself is Arm. The call destination can either be
485 // Thumb or Arm. We use BL to stay in Arm and BLX to change to Thumb.
486 bool TargetIsThumb
= hasTargetFlags(TargetSymbol
, ThumbSymbol
);
487 bool InstrIsBlx
= (~R
.Wd
& FixupInfo
<Arm_Call
>::BitBlx
) == 0;
488 if (TargetIsThumb
!= InstrIsBlx
) {
489 if (LLVM_LIKELY(TargetIsThumb
)) {
490 // Change opcode BL -> BLX
491 R
.Wd
= R
.Wd
| FixupInfo
<Arm_Call
>::BitBlx
;
492 R
.Wd
= R
.Wd
& ~FixupInfo
<Arm_Call
>::BitH
;
494 // Change opcode BLX -> BL
495 R
.Wd
= R
.Wd
& ~FixupInfo
<Arm_Call
>::BitBlx
;
499 if (!isInt
<26>(Value
))
500 return makeTargetOutOfRangeError(G
, B
, E
);
501 writeImmediate
<Arm_Call
>(R
, encodeImmBA1BlA1BlxA2(Value
));
503 return Error::success();
505 case Arm_MovwAbsNC
: {
506 if (!checkOpcode
<Arm_MovwAbsNC
>(R
))
507 return makeUnexpectedOpcodeError(G
, R
, Kind
);
508 uint16_t Value
= (TargetAddress
+ Addend
) & 0xffff;
509 writeImmediate
<Arm_MovwAbsNC
>(R
, encodeImmMovtA1MovwA2(Value
));
510 return Error::success();
513 if (!checkOpcode
<Arm_MovtAbs
>(R
))
514 return makeUnexpectedOpcodeError(G
, R
, Kind
);
515 uint16_t Value
= ((TargetAddress
+ Addend
) >> 16) & 0xffff;
516 writeImmediate
<Arm_MovtAbs
>(R
, encodeImmMovtA1MovwA2(Value
));
517 return Error::success();
520 return make_error
<JITLinkError
>(
521 "In graph " + G
.getName() + ", section " + B
.getSection().getName() +
522 " encountered unfixable aarch32 edge kind " +
523 G
.getEdgeKindName(E
.getKind()));
527 Error
applyFixupThumb(LinkGraph
&G
, Block
&B
, const Edge
&E
,
528 const ArmConfig
&ArmCfg
) {
529 WritableThumbRelocation
R(B
.getAlreadyMutableContent().data() +
532 Edge::Kind Kind
= E
.getKind();
533 uint64_t FixupAddress
= (B
.getAddress() + E
.getOffset()).getValue();
534 int64_t Addend
= E
.getAddend();
535 Symbol
&TargetSymbol
= E
.getTarget();
536 uint64_t TargetAddress
= TargetSymbol
.getAddress().getValue();
540 if (!checkOpcode
<Thumb_Jump24
>(R
))
541 return makeUnexpectedOpcodeError(G
, R
, Kind
);
542 if (!hasTargetFlags(TargetSymbol
, ThumbSymbol
))
543 return make_error
<JITLinkError
>("Branch relocation needs interworking "
544 "stub when bridging to ARM: " +
545 StringRef(G
.getEdgeKindName(Kind
)));
547 int64_t Value
= TargetAddress
- FixupAddress
+ Addend
;
548 if (LLVM_LIKELY(ArmCfg
.J1J2BranchEncoding
)) {
549 if (!isInt
<25>(Value
))
550 return makeTargetOutOfRangeError(G
, B
, E
);
551 writeImmediate
<Thumb_Jump24
>(R
, encodeImmBT4BlT1BlxT2_J1J2(Value
));
553 if (!isInt
<22>(Value
))
554 return makeTargetOutOfRangeError(G
, B
, E
);
555 writeImmediate
<Thumb_Jump24
>(R
, encodeImmBT4BlT1BlxT2(Value
));
558 return Error::success();
562 if (!checkOpcode
<Thumb_Call
>(R
))
563 return makeUnexpectedOpcodeError(G
, R
, Kind
);
565 int64_t Value
= TargetAddress
- FixupAddress
+ Addend
;
567 // The call instruction itself is Thumb. The call destination can either be
568 // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm.
569 bool TargetIsArm
= !hasTargetFlags(TargetSymbol
, ThumbSymbol
);
570 bool InstrIsBlx
= (R
.Lo
& FixupInfo
<Thumb_Call
>::LoBitNoBlx
) == 0;
571 if (TargetIsArm
!= InstrIsBlx
) {
572 if (LLVM_LIKELY(TargetIsArm
)) {
573 // Change opcode BL -> BLX and fix range value: account for 4-byte
574 // aligned destination while instruction may only be 2-byte aligned
575 R
.Lo
= R
.Lo
& ~FixupInfo
<Thumb_Call
>::LoBitNoBlx
;
576 R
.Lo
= R
.Lo
& ~FixupInfo
<Thumb_Call
>::LoBitH
;
577 Value
= alignTo(Value
, 4);
579 // Change opcode BLX -> BL
580 R
.Lo
= R
.Lo
& ~FixupInfo
<Thumb_Call
>::LoBitNoBlx
;
584 if (LLVM_LIKELY(ArmCfg
.J1J2BranchEncoding
)) {
585 if (!isInt
<25>(Value
))
586 return makeTargetOutOfRangeError(G
, B
, E
);
587 writeImmediate
<Thumb_Call
>(R
, encodeImmBT4BlT1BlxT2_J1J2(Value
));
589 if (!isInt
<22>(Value
))
590 return makeTargetOutOfRangeError(G
, B
, E
);
591 writeImmediate
<Thumb_Call
>(R
, encodeImmBT4BlT1BlxT2(Value
));
594 assert(((R
.Lo
& FixupInfo
<Thumb_Call
>::LoBitNoBlx
) ||
595 (R
.Lo
& FixupInfo
<Thumb_Call
>::LoBitH
) == 0) &&
596 "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
597 return Error::success();
600 case Thumb_MovwAbsNC
: {
601 if (!checkOpcode
<Thumb_MovwAbsNC
>(R
))
602 return makeUnexpectedOpcodeError(G
, R
, Kind
);
603 uint16_t Value
= (TargetAddress
+ Addend
) & 0xffff;
604 writeImmediate
<Thumb_MovwAbsNC
>(R
, encodeImmMovtT1MovwT3(Value
));
605 return Error::success();
608 case Thumb_MovtAbs
: {
609 if (!checkOpcode
<Thumb_MovtAbs
>(R
))
610 return makeUnexpectedOpcodeError(G
, R
, Kind
);
611 uint16_t Value
= ((TargetAddress
+ Addend
) >> 16) & 0xffff;
612 writeImmediate
<Thumb_MovtAbs
>(R
, encodeImmMovtT1MovwT3(Value
));
613 return Error::success();
617 return make_error
<JITLinkError
>(
618 "In graph " + G
.getName() + ", section " + B
.getSection().getName() +
619 " encountered unfixable aarch32 edge kind " +
620 G
.getEdgeKindName(E
.getKind()));
624 const uint8_t Thumbv7ABS
[] = {
625 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit
626 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit
631 Symbol
&StubsManager
<Thumbv7
>::createEntry(LinkGraph
&G
, Symbol
&Target
) {
632 constexpr uint64_t Alignment
= 4;
633 Block
&B
= addStub(G
, Thumbv7ABS
, Alignment
);
635 const char *StubPtr
= B
.getContent().data();
636 HalfWords Reg12
= encodeRegMovtT1MovwT3(12);
637 assert(checkRegister
<Thumb_MovwAbsNC
>(StubPtr
, Reg12
) &&
638 checkRegister
<Thumb_MovtAbs
>(StubPtr
+ 4, Reg12
) &&
639 "Linker generated stubs may only corrupt register r12 (IP)");
641 B
.addEdge(Thumb_MovwAbsNC
, 0, Target
, 0);
642 B
.addEdge(Thumb_MovtAbs
, 4, Target
, 0);
643 Symbol
&Stub
= G
.addAnonymousSymbol(B
, 0, B
.getSize(), true, false);
644 Stub
.setTargetFlags(ThumbSymbol
);
648 const char *getEdgeKindName(Edge::Kind K
) {
649 #define KIND_NAME_CASE(K) \
654 KIND_NAME_CASE(Data_Delta32
)
655 KIND_NAME_CASE(Data_Pointer32
)
656 KIND_NAME_CASE(Arm_Call
)
657 KIND_NAME_CASE(Arm_Jump24
)
658 KIND_NAME_CASE(Arm_MovwAbsNC
)
659 KIND_NAME_CASE(Arm_MovtAbs
)
660 KIND_NAME_CASE(Thumb_Call
)
661 KIND_NAME_CASE(Thumb_Jump24
)
662 KIND_NAME_CASE(Thumb_MovwAbsNC
)
663 KIND_NAME_CASE(Thumb_MovtAbs
)
665 return getGenericEdgeKindName(K
);
667 #undef KIND_NAME_CASE
670 const char *getCPUArchName(ARMBuildAttrs::CPUArch K
) {
671 #define CPUARCH_NAME_CASE(K) \
675 using namespace ARMBuildAttrs
;
677 CPUARCH_NAME_CASE(Pre_v4
)
678 CPUARCH_NAME_CASE(v4
)
679 CPUARCH_NAME_CASE(v4T
)
680 CPUARCH_NAME_CASE(v5T
)
681 CPUARCH_NAME_CASE(v5TE
)
682 CPUARCH_NAME_CASE(v5TEJ
)
683 CPUARCH_NAME_CASE(v6
)
684 CPUARCH_NAME_CASE(v6KZ
)
685 CPUARCH_NAME_CASE(v6T2
)
686 CPUARCH_NAME_CASE(v6K
)
687 CPUARCH_NAME_CASE(v7
)
688 CPUARCH_NAME_CASE(v6_M
)
689 CPUARCH_NAME_CASE(v6S_M
)
690 CPUARCH_NAME_CASE(v7E_M
)
691 CPUARCH_NAME_CASE(v8_A
)
692 CPUARCH_NAME_CASE(v8_R
)
693 CPUARCH_NAME_CASE(v8_M_Base
)
694 CPUARCH_NAME_CASE(v8_M_Main
)
695 CPUARCH_NAME_CASE(v8_1_M_Main
)
696 CPUARCH_NAME_CASE(v9_A
)
698 llvm_unreachable("Missing CPUArch in switch?");
699 #undef CPUARCH_NAME_CASE
702 } // namespace aarch32
703 } // namespace jitlink