xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp (revision 5c16e71d30c388dd43b217de10a3ccb4b0219d0d)
106c3fb27SDimitry Andric //===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // Generic utilities for graphs representing arm/thumb objects.
1006c3fb27SDimitry Andric //
1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch32.h"
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
1606c3fb27SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
1706c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
1806c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
1906c3fb27SDimitry Andric #include "llvm/Support/Endian.h"
2006c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h"
2106c3fb27SDimitry Andric 
2206c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink"
2306c3fb27SDimitry Andric 
2406c3fb27SDimitry Andric namespace llvm {
2506c3fb27SDimitry Andric namespace jitlink {
2606c3fb27SDimitry Andric namespace aarch32 {
2706c3fb27SDimitry Andric 
2806c3fb27SDimitry Andric /// Encode 22-bit immediate value for branch instructions without J1J2 range
2906c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
3006c3fb27SDimitry Andric ///
3106c3fb27SDimitry Andric ///   00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ]
3206c3fb27SDimitry Andric ///                                            J1^ ^J2 will always be 1
3306c3fb27SDimitry Andric ///
3406c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) {
3506c3fb27SDimitry Andric   constexpr uint32_t J1J2 = 0x2800;
3606c3fb27SDimitry Andric   uint32_t Imm11H = (Value >> 12) & 0x07ff;
3706c3fb27SDimitry Andric   uint32_t Imm11L = (Value >> 1) & 0x07ff;
3806c3fb27SDimitry Andric   return HalfWords{Imm11H, Imm11L | J1J2};
3906c3fb27SDimitry Andric }
4006c3fb27SDimitry Andric 
4106c3fb27SDimitry Andric /// Decode 22-bit immediate value for branch instructions without J1J2 range
4206c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
4306c3fb27SDimitry Andric ///
4406c3fb27SDimitry Andric ///   [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0
4506c3fb27SDimitry Andric ///                   J1^ ^J2 will always be 1
4606c3fb27SDimitry Andric ///
4706c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) {
4806c3fb27SDimitry Andric   uint32_t Imm11H = Hi & 0x07ff;
4906c3fb27SDimitry Andric   uint32_t Imm11L = Lo & 0x07ff;
5006c3fb27SDimitry Andric   return SignExtend64<22>(Imm11H << 12 | Imm11L << 1);
5106c3fb27SDimitry Andric }
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric /// Encode 25-bit immediate value for branch instructions with J1J2 range
5406c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
5506c3fb27SDimitry Andric ///
5606c3fb27SDimitry Andric ///   S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ]
5706c3fb27SDimitry Andric ///
5806c3fb27SDimitry Andric HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) {
5906c3fb27SDimitry Andric   uint32_t S = (Value >> 14) & 0x0400;
6006c3fb27SDimitry Andric   uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000);
6106c3fb27SDimitry Andric   uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800);
6206c3fb27SDimitry Andric   uint32_t Imm10 = (Value >> 12) & 0x03ff;
6306c3fb27SDimitry Andric   uint32_t Imm11 = (Value >> 1) & 0x07ff;
6406c3fb27SDimitry Andric   return HalfWords{S | Imm10, J1 | J2 | Imm11};
6506c3fb27SDimitry Andric }
6606c3fb27SDimitry Andric 
6706c3fb27SDimitry Andric /// Decode 25-bit immediate value for branch instructions with J1J2 range
6806c3fb27SDimitry Andric /// extension (formats B T4, BL T1 and BLX T2).
6906c3fb27SDimitry Andric ///
7006c3fb27SDimitry Andric ///   [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0
7106c3fb27SDimitry Andric ///
7206c3fb27SDimitry Andric int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) {
7306c3fb27SDimitry Andric   uint32_t S = Hi & 0x0400;
7406c3fb27SDimitry Andric   uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000;
7506c3fb27SDimitry Andric   uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000;
7606c3fb27SDimitry Andric   uint32_t Imm10 = Hi & 0x03ff;
7706c3fb27SDimitry Andric   uint32_t Imm11 = Lo & 0x07ff;
7806c3fb27SDimitry Andric   return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1);
7906c3fb27SDimitry Andric }
8006c3fb27SDimitry Andric 
8106c3fb27SDimitry Andric /// Encode 16-bit immediate value for move instruction formats MOVT T1 and
8206c3fb27SDimitry Andric /// MOVW T3.
8306c3fb27SDimitry Andric ///
8406c3fb27SDimitry Andric ///   Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ]
8506c3fb27SDimitry Andric ///
8606c3fb27SDimitry Andric HalfWords encodeImmMovtT1MovwT3(uint16_t Value) {
8706c3fb27SDimitry Andric   uint32_t Imm4 = (Value >> 12) & 0x0f;
8806c3fb27SDimitry Andric   uint32_t Imm1 = (Value >> 11) & 0x01;
8906c3fb27SDimitry Andric   uint32_t Imm3 = (Value >> 8) & 0x07;
9006c3fb27SDimitry Andric   uint32_t Imm8 = Value & 0xff;
9106c3fb27SDimitry Andric   return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8};
9206c3fb27SDimitry Andric }
9306c3fb27SDimitry Andric 
9406c3fb27SDimitry Andric /// Decode 16-bit immediate value from move instruction formats MOVT T1 and
9506c3fb27SDimitry Andric /// MOVW T3.
9606c3fb27SDimitry Andric ///
9706c3fb27SDimitry Andric ///   [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8
9806c3fb27SDimitry Andric ///
9906c3fb27SDimitry Andric uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
10006c3fb27SDimitry Andric   uint32_t Imm4 = Hi & 0x0f;
10106c3fb27SDimitry Andric   uint32_t Imm1 = (Hi >> 10) & 0x01;
10206c3fb27SDimitry Andric   uint32_t Imm3 = (Lo >> 12) & 0x07;
10306c3fb27SDimitry Andric   uint32_t Imm8 = Lo & 0xff;
10406c3fb27SDimitry Andric   uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8;
10506c3fb27SDimitry Andric   assert(Imm16 <= 0xffff && "Decoded value out-of-range");
10606c3fb27SDimitry Andric   return Imm16;
10706c3fb27SDimitry Andric }
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric /// Encode register ID for instruction formats MOVT T1 and MOVW T3.
11006c3fb27SDimitry Andric ///
11106c3fb27SDimitry Andric ///   Rd4 -> [0000000000000000, 0000:Rd4:00000000]
11206c3fb27SDimitry Andric ///
11306c3fb27SDimitry Andric HalfWords encodeRegMovtT1MovwT3(int64_t Value) {
11406c3fb27SDimitry Andric   uint32_t Rd4 = (Value & 0x0f) << 8;
11506c3fb27SDimitry Andric   return HalfWords{0, Rd4};
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric 
11806c3fb27SDimitry Andric /// Decode register ID from instruction formats MOVT T1 and MOVW T3.
11906c3fb27SDimitry Andric ///
12006c3fb27SDimitry Andric ///   [0000000000000000, 0000:Rd4:00000000] -> Rd4
12106c3fb27SDimitry Andric ///
12206c3fb27SDimitry Andric int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) {
12306c3fb27SDimitry Andric   uint32_t Rd4 = (Lo >> 8) & 0x0f;
12406c3fb27SDimitry Andric   return Rd4;
12506c3fb27SDimitry Andric }
12606c3fb27SDimitry Andric 
12706c3fb27SDimitry Andric /// 32-bit Thumb instructions are stored as two little-endian halfwords.
12806c3fb27SDimitry Andric /// An instruction at address A encodes bytes A+1, A in the first halfword (Hi),
12906c3fb27SDimitry Andric /// followed by bytes A+3, A+2 in the second halfword (Lo).
13006c3fb27SDimitry Andric struct WritableThumbRelocation {
13106c3fb27SDimitry Andric   /// Create a writable reference to a Thumb32 fixup.
13206c3fb27SDimitry Andric   WritableThumbRelocation(char *FixupPtr)
13306c3fb27SDimitry Andric       : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)},
13406c3fb27SDimitry Andric         Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {}
13506c3fb27SDimitry Andric 
13606c3fb27SDimitry Andric   support::ulittle16_t &Hi; // First halfword
13706c3fb27SDimitry Andric   support::ulittle16_t &Lo; // Second halfword
13806c3fb27SDimitry Andric };
13906c3fb27SDimitry Andric 
14006c3fb27SDimitry Andric struct ThumbRelocation {
14106c3fb27SDimitry Andric   /// Create a read-only reference to a Thumb32 fixup.
14206c3fb27SDimitry Andric   ThumbRelocation(const char *FixupPtr)
14306c3fb27SDimitry Andric       : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)},
14406c3fb27SDimitry Andric         Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {}
14506c3fb27SDimitry Andric 
14606c3fb27SDimitry Andric   /// Create a read-only Thumb32 fixup from a writeable one.
14706c3fb27SDimitry Andric   ThumbRelocation(WritableThumbRelocation &Writable)
14806c3fb27SDimitry Andric       : Hi{Writable.Hi}, Lo(Writable.Lo) {}
14906c3fb27SDimitry Andric 
15006c3fb27SDimitry Andric   const support::ulittle16_t &Hi; // First halfword
15106c3fb27SDimitry Andric   const support::ulittle16_t &Lo; // Second halfword
15206c3fb27SDimitry Andric };
15306c3fb27SDimitry Andric 
15406c3fb27SDimitry Andric Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R,
15506c3fb27SDimitry Andric                                 Edge::Kind Kind) {
15606c3fb27SDimitry Andric   return make_error<JITLinkError>(
15706c3fb27SDimitry Andric       formatv("Invalid opcode [ 0x{0:x4}, 0x{1:x4} ] for relocation: {2}",
15806c3fb27SDimitry Andric               static_cast<uint16_t>(R.Hi), static_cast<uint16_t>(R.Lo),
15906c3fb27SDimitry Andric               G.getEdgeKindName(Kind)));
16006c3fb27SDimitry Andric }
16106c3fb27SDimitry Andric 
16206c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind> bool checkOpcode(const ThumbRelocation &R) {
16306c3fb27SDimitry Andric   uint16_t Hi = R.Hi & FixupInfo<Kind>::OpcodeMask.Hi;
16406c3fb27SDimitry Andric   uint16_t Lo = R.Lo & FixupInfo<Kind>::OpcodeMask.Lo;
16506c3fb27SDimitry Andric   return Hi == FixupInfo<Kind>::Opcode.Hi && Lo == FixupInfo<Kind>::Opcode.Lo;
16606c3fb27SDimitry Andric }
16706c3fb27SDimitry Andric 
16806c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
16906c3fb27SDimitry Andric bool checkRegister(const ThumbRelocation &R, HalfWords Reg) {
17006c3fb27SDimitry Andric   uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi;
17106c3fb27SDimitry Andric   uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo;
17206c3fb27SDimitry Andric   return Hi == Reg.Hi && Lo == Reg.Lo;
17306c3fb27SDimitry Andric }
17406c3fb27SDimitry Andric 
17506c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
176*5c16e71dSDimitry Andric void writeRegister(WritableThumbRelocation &R, HalfWords Reg) {
17706c3fb27SDimitry Andric   static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask;
17806c3fb27SDimitry Andric   assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Hi & Reg.Hi) == Reg.Hi &&
17906c3fb27SDimitry Andric          "Value bits exceed bit range of given mask");
18006c3fb27SDimitry Andric   R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi;
18106c3fb27SDimitry Andric   R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo;
18206c3fb27SDimitry Andric }
18306c3fb27SDimitry Andric 
18406c3fb27SDimitry Andric template <EdgeKind_aarch32 Kind>
18506c3fb27SDimitry Andric void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) {
18606c3fb27SDimitry Andric   static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask;
18706c3fb27SDimitry Andric   assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Hi & Imm.Hi) == Imm.Hi &&
18806c3fb27SDimitry Andric          "Value bits exceed bit range of given mask");
18906c3fb27SDimitry Andric   R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi;
19006c3fb27SDimitry Andric   R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo;
19106c3fb27SDimitry Andric }
19206c3fb27SDimitry Andric 
19306c3fb27SDimitry Andric Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E) {
19406c3fb27SDimitry Andric   support::endianness Endian = G.getEndianness();
19506c3fb27SDimitry Andric   assert(Endian != support::native && "Declare as little or big explicitly");
19606c3fb27SDimitry Andric 
19706c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
19806c3fb27SDimitry Andric   const char *BlockWorkingMem = B.getContent().data();
19906c3fb27SDimitry Andric   const char *FixupPtr = BlockWorkingMem + E.getOffset();
20006c3fb27SDimitry Andric 
20106c3fb27SDimitry Andric   switch (Kind) {
20206c3fb27SDimitry Andric   case Data_Delta32:
20306c3fb27SDimitry Andric   case Data_Pointer32:
20406c3fb27SDimitry Andric     return SignExtend64<32>(support::endian::read32(FixupPtr, Endian));
20506c3fb27SDimitry Andric   default:
20606c3fb27SDimitry Andric     return make_error<JITLinkError>(
20706c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
20806c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
20906c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
21006c3fb27SDimitry Andric   }
21106c3fb27SDimitry Andric }
21206c3fb27SDimitry Andric 
21306c3fb27SDimitry Andric Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) {
21406c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
21506c3fb27SDimitry Andric 
21606c3fb27SDimitry Andric   switch (Kind) {
21706c3fb27SDimitry Andric   case Arm_Call:
21806c3fb27SDimitry Andric     return make_error<JITLinkError>(
21906c3fb27SDimitry Andric         "Addend extraction for relocation type not yet implemented: " +
22006c3fb27SDimitry Andric         StringRef(G.getEdgeKindName(Kind)));
22106c3fb27SDimitry Andric   default:
22206c3fb27SDimitry Andric     return make_error<JITLinkError>(
22306c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
22406c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
22506c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
22606c3fb27SDimitry Andric   }
22706c3fb27SDimitry Andric }
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E,
23006c3fb27SDimitry Andric                                   const ArmConfig &ArmCfg) {
23106c3fb27SDimitry Andric   ThumbRelocation R(B.getContent().data() + E.getOffset());
23206c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
23306c3fb27SDimitry Andric 
23406c3fb27SDimitry Andric   switch (Kind) {
23506c3fb27SDimitry Andric   case Thumb_Call:
23606c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Call>(R))
23706c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
23806c3fb27SDimitry Andric     return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
23906c3fb27SDimitry Andric                ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
24006c3fb27SDimitry Andric                : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
24106c3fb27SDimitry Andric 
24206c3fb27SDimitry Andric   case Thumb_Jump24:
24306c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Jump24>(R))
24406c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
24506c3fb27SDimitry Andric     if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional)
24606c3fb27SDimitry Andric       return make_error<JITLinkError>("Relocation expects an unconditional "
24706c3fb27SDimitry Andric                                       "B.W branch instruction: " +
24806c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
24906c3fb27SDimitry Andric     return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)
25006c3fb27SDimitry Andric                   ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo)
25106c3fb27SDimitry Andric                   : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo);
25206c3fb27SDimitry Andric 
25306c3fb27SDimitry Andric   case Thumb_MovwAbsNC:
25406c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovwAbsNC>(R))
25506c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
25606c3fb27SDimitry Andric     // Initial addend is interpreted as a signed value
25706c3fb27SDimitry Andric     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric   case Thumb_MovtAbs:
26006c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovtAbs>(R))
26106c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
26206c3fb27SDimitry Andric     // Initial addend is interpreted as a signed value
26306c3fb27SDimitry Andric     return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo));
26406c3fb27SDimitry Andric 
26506c3fb27SDimitry Andric   default:
26606c3fb27SDimitry Andric     return make_error<JITLinkError>(
26706c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
26806c3fb27SDimitry Andric         " can not read implicit addend for aarch32 edge kind " +
26906c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
27006c3fb27SDimitry Andric   }
27106c3fb27SDimitry Andric }
27206c3fb27SDimitry Andric 
27306c3fb27SDimitry Andric Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
27406c3fb27SDimitry Andric   using namespace support;
27506c3fb27SDimitry Andric 
27606c3fb27SDimitry Andric   char *BlockWorkingMem = B.getAlreadyMutableContent().data();
27706c3fb27SDimitry Andric   char *FixupPtr = BlockWorkingMem + E.getOffset();
27806c3fb27SDimitry Andric 
27906c3fb27SDimitry Andric   auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) {
28006c3fb27SDimitry Andric     assert(Endian != native && "Must be explicit: little or big");
28106c3fb27SDimitry Andric     assert(isInt<32>(Value) && "Must be in signed 32-bit range");
28206c3fb27SDimitry Andric     uint32_t Imm = static_cast<int32_t>(Value);
28306c3fb27SDimitry Andric     if (LLVM_LIKELY(Endian == little))
28406c3fb27SDimitry Andric       endian::write32<little>(FixupPtr, Imm);
28506c3fb27SDimitry Andric     else
28606c3fb27SDimitry Andric       endian::write32<big>(FixupPtr, Imm);
28706c3fb27SDimitry Andric   };
28806c3fb27SDimitry Andric 
28906c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
29006c3fb27SDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
29106c3fb27SDimitry Andric   int64_t Addend = E.getAddend();
29206c3fb27SDimitry Andric   Symbol &TargetSymbol = E.getTarget();
29306c3fb27SDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
29406c3fb27SDimitry Andric   assert(!TargetSymbol.hasTargetFlags(ThumbSymbol));
29506c3fb27SDimitry Andric 
29606c3fb27SDimitry Andric   // Regular data relocations have size 4, alignment 1 and write the full 32-bit
29706c3fb27SDimitry Andric   // result to the place; no need for overflow checking. There are three
29806c3fb27SDimitry Andric   // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31
29906c3fb27SDimitry Andric   switch (Kind) {
30006c3fb27SDimitry Andric   case Data_Delta32: {
30106c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
30206c3fb27SDimitry Andric     if (!isInt<32>(Value))
30306c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
30406c3fb27SDimitry Andric     Write32(Value);
30506c3fb27SDimitry Andric     return Error::success();
30606c3fb27SDimitry Andric   }
30706c3fb27SDimitry Andric   case Data_Pointer32: {
30806c3fb27SDimitry Andric     int64_t Value = TargetAddress + Addend;
30906c3fb27SDimitry Andric     if (!isInt<32>(Value))
31006c3fb27SDimitry Andric       return makeTargetOutOfRangeError(G, B, E);
31106c3fb27SDimitry Andric     Write32(Value);
31206c3fb27SDimitry Andric     return Error::success();
31306c3fb27SDimitry Andric   }
31406c3fb27SDimitry Andric   default:
31506c3fb27SDimitry Andric     return make_error<JITLinkError>(
31606c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
31706c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
31806c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
31906c3fb27SDimitry Andric   }
32006c3fb27SDimitry Andric }
32106c3fb27SDimitry Andric 
32206c3fb27SDimitry Andric Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) {
32306c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
32406c3fb27SDimitry Andric 
32506c3fb27SDimitry Andric   switch (Kind) {
32606c3fb27SDimitry Andric   case Arm_Call:
32706c3fb27SDimitry Andric     return make_error<JITLinkError>(
32806c3fb27SDimitry Andric         "Fix-up for relocation type not yet implemented: " +
32906c3fb27SDimitry Andric         StringRef(G.getEdgeKindName(Kind)));
33006c3fb27SDimitry Andric   default:
33106c3fb27SDimitry Andric     return make_error<JITLinkError>(
33206c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
33306c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
33406c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
33506c3fb27SDimitry Andric   }
33606c3fb27SDimitry Andric }
33706c3fb27SDimitry Andric 
33806c3fb27SDimitry Andric Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
33906c3fb27SDimitry Andric                       const ArmConfig &ArmCfg) {
34006c3fb27SDimitry Andric   WritableThumbRelocation R(B.getAlreadyMutableContent().data() +
34106c3fb27SDimitry Andric                             E.getOffset());
34206c3fb27SDimitry Andric 
34306c3fb27SDimitry Andric   Edge::Kind Kind = E.getKind();
34406c3fb27SDimitry Andric   uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
34506c3fb27SDimitry Andric   int64_t Addend = E.getAddend();
34606c3fb27SDimitry Andric   Symbol &TargetSymbol = E.getTarget();
34706c3fb27SDimitry Andric   uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
34806c3fb27SDimitry Andric   if (TargetSymbol.hasTargetFlags(ThumbSymbol))
34906c3fb27SDimitry Andric     TargetAddress |= 0x01;
35006c3fb27SDimitry Andric 
35106c3fb27SDimitry Andric   switch (Kind) {
35206c3fb27SDimitry Andric   case Thumb_Jump24: {
35306c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Jump24>(R))
35406c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
35506c3fb27SDimitry Andric     if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional)
35606c3fb27SDimitry Andric       return make_error<JITLinkError>("Relocation expects an unconditional "
35706c3fb27SDimitry Andric                                       "B.W branch instruction: " +
35806c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
35906c3fb27SDimitry Andric     if (!(TargetSymbol.hasTargetFlags(ThumbSymbol)))
36006c3fb27SDimitry Andric       return make_error<JITLinkError>("Branch relocation needs interworking "
36106c3fb27SDimitry Andric                                       "stub when bridging to ARM: " +
36206c3fb27SDimitry Andric                                       StringRef(G.getEdgeKindName(Kind)));
36306c3fb27SDimitry Andric 
36406c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
36506c3fb27SDimitry Andric     if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) {
36606c3fb27SDimitry Andric       if (!isInt<25>(Value))
36706c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
36806c3fb27SDimitry Andric       writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value));
36906c3fb27SDimitry Andric     } else {
37006c3fb27SDimitry Andric       if (!isInt<22>(Value))
37106c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
37206c3fb27SDimitry Andric       writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value));
37306c3fb27SDimitry Andric     }
37406c3fb27SDimitry Andric 
37506c3fb27SDimitry Andric     return Error::success();
37606c3fb27SDimitry Andric   }
37706c3fb27SDimitry Andric 
37806c3fb27SDimitry Andric   case Thumb_Call: {
37906c3fb27SDimitry Andric     if (!checkOpcode<Thumb_Call>(R))
38006c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
38106c3fb27SDimitry Andric 
38206c3fb27SDimitry Andric     int64_t Value = TargetAddress - FixupAddress + Addend;
38306c3fb27SDimitry Andric 
38406c3fb27SDimitry Andric     // The call instruction itself is Thumb. The call destination can either be
38506c3fb27SDimitry Andric     // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm.
38606c3fb27SDimitry Andric     bool TargetIsArm = !TargetSymbol.hasTargetFlags(ThumbSymbol);
38706c3fb27SDimitry Andric     bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0;
38806c3fb27SDimitry Andric     if (TargetIsArm != InstrIsBlx) {
38906c3fb27SDimitry Andric       if (LLVM_LIKELY(TargetIsArm)) {
39006c3fb27SDimitry Andric         // Change opcode BL -> BLX and fix range value (account for 4-byte
39106c3fb27SDimitry Andric         // aligned destination while instruction may only be 2-byte aligned
39206c3fb27SDimitry Andric         // and clear Thumb bit).
39306c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx;
39406c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH;
39506c3fb27SDimitry Andric         Value = alignTo(Value, 4);
39606c3fb27SDimitry Andric       } else {
39706c3fb27SDimitry Andric         // Change opcode BLX -> BL and set Thumb bit
39806c3fb27SDimitry Andric         R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx;
39906c3fb27SDimitry Andric         Value |= 0x01;
40006c3fb27SDimitry Andric       }
40106c3fb27SDimitry Andric     }
40206c3fb27SDimitry Andric 
40306c3fb27SDimitry Andric     if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) {
40406c3fb27SDimitry Andric       if (!isInt<25>(Value))
40506c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
40606c3fb27SDimitry Andric       writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value));
40706c3fb27SDimitry Andric     } else {
40806c3fb27SDimitry Andric       if (!isInt<22>(Value))
40906c3fb27SDimitry Andric         return makeTargetOutOfRangeError(G, B, E);
41006c3fb27SDimitry Andric       writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value));
41106c3fb27SDimitry Andric     }
41206c3fb27SDimitry Andric 
41306c3fb27SDimitry Andric     assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) ||
41406c3fb27SDimitry Andric             (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) &&
41506c3fb27SDimitry Andric            "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
41606c3fb27SDimitry Andric     return Error::success();
41706c3fb27SDimitry Andric   }
41806c3fb27SDimitry Andric 
41906c3fb27SDimitry Andric   case Thumb_MovwAbsNC: {
42006c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovwAbsNC>(R))
42106c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
42206c3fb27SDimitry Andric     uint16_t Value = (TargetAddress + Addend) & 0xffff;
42306c3fb27SDimitry Andric     writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value));
42406c3fb27SDimitry Andric     return Error::success();
42506c3fb27SDimitry Andric   }
42606c3fb27SDimitry Andric 
42706c3fb27SDimitry Andric   case Thumb_MovtAbs: {
42806c3fb27SDimitry Andric     if (!checkOpcode<Thumb_MovtAbs>(R))
42906c3fb27SDimitry Andric       return makeUnexpectedOpcodeError(G, R, Kind);
43006c3fb27SDimitry Andric     uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff;
43106c3fb27SDimitry Andric     writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value));
43206c3fb27SDimitry Andric     return Error::success();
43306c3fb27SDimitry Andric   }
43406c3fb27SDimitry Andric 
43506c3fb27SDimitry Andric   default:
43606c3fb27SDimitry Andric     return make_error<JITLinkError>(
43706c3fb27SDimitry Andric         "In graph " + G.getName() + ", section " + B.getSection().getName() +
43806c3fb27SDimitry Andric         " encountered unfixable aarch32 edge kind " +
43906c3fb27SDimitry Andric         G.getEdgeKindName(E.getKind()));
44006c3fb27SDimitry Andric   }
44106c3fb27SDimitry Andric }
44206c3fb27SDimitry Andric 
44306c3fb27SDimitry Andric const uint8_t Thumbv7ABS[] = {
44406c3fb27SDimitry Andric     0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000    ; lower 16-bit
44506c3fb27SDimitry Andric     0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000    ; upper 16-bit
44606c3fb27SDimitry Andric     0x60, 0x47              // bx   r12
44706c3fb27SDimitry Andric };
44806c3fb27SDimitry Andric 
44906c3fb27SDimitry Andric template <>
45006c3fb27SDimitry Andric Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) {
45106c3fb27SDimitry Andric   constexpr uint64_t Alignment = 4;
45206c3fb27SDimitry Andric   Block &B = addStub(G, Thumbv7ABS, Alignment);
45306c3fb27SDimitry Andric   LLVM_DEBUG({
45406c3fb27SDimitry Andric     const char *StubPtr = B.getContent().data();
45506c3fb27SDimitry Andric     HalfWords Reg12 = encodeRegMovtT1MovwT3(12);
45606c3fb27SDimitry Andric     assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
45706c3fb27SDimitry Andric            checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
45806c3fb27SDimitry Andric            "Linker generated stubs may only corrupt register r12 (IP)");
45906c3fb27SDimitry Andric   });
46006c3fb27SDimitry Andric   B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
46106c3fb27SDimitry Andric   B.addEdge(Thumb_MovtAbs, 4, Target, 0);
46206c3fb27SDimitry Andric   Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false);
46306c3fb27SDimitry Andric   Stub.setTargetFlags(ThumbSymbol);
46406c3fb27SDimitry Andric   return Stub;
46506c3fb27SDimitry Andric }
46606c3fb27SDimitry Andric 
46706c3fb27SDimitry Andric const char *getEdgeKindName(Edge::Kind K) {
46806c3fb27SDimitry Andric #define KIND_NAME_CASE(K)                                                      \
46906c3fb27SDimitry Andric   case K:                                                                      \
47006c3fb27SDimitry Andric     return #K;
47106c3fb27SDimitry Andric 
47206c3fb27SDimitry Andric   switch (K) {
47306c3fb27SDimitry Andric     KIND_NAME_CASE(Data_Delta32)
47406c3fb27SDimitry Andric     KIND_NAME_CASE(Arm_Call)
47506c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_Call)
47606c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_Jump24)
47706c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_MovwAbsNC)
47806c3fb27SDimitry Andric     KIND_NAME_CASE(Thumb_MovtAbs)
47906c3fb27SDimitry Andric   default:
48006c3fb27SDimitry Andric     return getGenericEdgeKindName(K);
48106c3fb27SDimitry Andric   }
48206c3fb27SDimitry Andric #undef KIND_NAME_CASE
48306c3fb27SDimitry Andric }
48406c3fb27SDimitry Andric 
48506c3fb27SDimitry Andric const char *getCPUArchName(ARMBuildAttrs::CPUArch K) {
48606c3fb27SDimitry Andric #define CPUARCH_NAME_CASE(K)                                                   \
48706c3fb27SDimitry Andric   case K:                                                                      \
48806c3fb27SDimitry Andric     return #K;
48906c3fb27SDimitry Andric 
49006c3fb27SDimitry Andric   using namespace ARMBuildAttrs;
49106c3fb27SDimitry Andric   switch (K) {
49206c3fb27SDimitry Andric     CPUARCH_NAME_CASE(Pre_v4)
49306c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v4)
49406c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v4T)
49506c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5T)
49606c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5TE)
49706c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v5TEJ)
49806c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6)
49906c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6KZ)
50006c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6T2)
50106c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6K)
50206c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v7)
50306c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6_M)
50406c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v6S_M)
50506c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v7E_M)
50606c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_A)
50706c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_R)
50806c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_M_Base)
50906c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_M_Main)
51006c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v8_1_M_Main)
51106c3fb27SDimitry Andric     CPUARCH_NAME_CASE(v9_A)
51206c3fb27SDimitry Andric   }
51306c3fb27SDimitry Andric   llvm_unreachable("Missing CPUArch in switch?");
51406c3fb27SDimitry Andric #undef CPUARCH_NAME_CASE
51506c3fb27SDimitry Andric }
51606c3fb27SDimitry Andric 
51706c3fb27SDimitry Andric } // namespace aarch32
51806c3fb27SDimitry Andric } // namespace jitlink
51906c3fb27SDimitry Andric } // namespace llvm
520