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