1 //===------ aarch32.h - Generic JITLink arm/thumb utilities -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Generic utilities for graphs representing arm/thumb objects. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_JITLINK_AARCH32 14 #define LLVM_EXECUTIONENGINE_JITLINK_AARCH32 15 16 #include "TableManager.h" 17 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 18 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" 19 #include "llvm/Support/ARMBuildAttributes.h" 20 #include "llvm/Support/Error.h" 21 22 namespace llvm { 23 namespace jitlink { 24 namespace aarch32 { 25 26 /// JITLink-internal AArch32 fixup kinds 27 enum EdgeKind_aarch32 : Edge::Kind { 28 29 /// 30 /// Relocations of class Data respect target endianness (unless otherwise 31 /// specified) 32 /// 33 FirstDataRelocation = Edge::FirstRelocation, 34 35 /// Relative 32-bit value relocation 36 Data_Delta32 = FirstDataRelocation, 37 38 /// Absolute 32-bit value relocation 39 Data_Pointer32, 40 41 LastDataRelocation = Data_Pointer32, 42 43 /// 44 /// Relocations of class Arm (covers fixed-width 4-byte instruction subset) 45 /// 46 FirstArmRelocation, 47 48 /// TODO: Arm_Call is here only as a placeholder for now. 49 Arm_Call = FirstArmRelocation, 50 51 LastArmRelocation = Arm_Call, 52 53 /// 54 /// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset) 55 /// 56 FirstThumbRelocation, 57 58 /// Write immediate value for PC-relative branch with link (can bridge between 59 /// Arm and Thumb). 60 Thumb_Call = FirstThumbRelocation, 61 62 /// Write immediate value for (unconditional) PC-relative branch without link. 63 Thumb_Jump24, 64 65 /// Write immediate value to the lower halfword of the destination register 66 Thumb_MovwAbsNC, 67 68 /// Write immediate value to the top halfword of the destination register 69 Thumb_MovtAbs, 70 71 LastThumbRelocation = Thumb_MovtAbs, 72 }; 73 74 /// Flags enum for AArch32-specific symbol properties 75 enum TargetFlags_aarch32 : TargetFlagsType { 76 ThumbSymbol = 1 << 0, 77 }; 78 79 /// Human-readable name for a given CPU architecture kind 80 const char *getCPUArchName(ARMBuildAttrs::CPUArch K); 81 82 /// Get a human-readable name for the given AArch32 edge kind. 83 const char *getEdgeKindName(Edge::Kind K); 84 85 /// AArch32 uses stubs for a number of purposes, like branch range extension 86 /// or interworking between Arm and Thumb instruction subsets. 87 /// 88 /// Stub implementations vary depending on CPU architecture (v4, v6, v7), 89 /// instruction subset and branch type (absolute/PC-relative). 90 /// 91 /// For each kind of stub, the StubsFlavor defines one concrete form that is 92 /// used throughout the LinkGraph. 93 /// 94 /// Stubs are often called "veneers" in the official docs and online. 95 /// 96 enum StubsFlavor { 97 Unsupported = 0, 98 Thumbv7, 99 }; 100 101 /// JITLink sub-arch configuration for Arm CPU models 102 struct ArmConfig { 103 bool J1J2BranchEncoding = false; 104 StubsFlavor Stubs = Unsupported; 105 }; 106 107 /// Obtain the sub-arch configuration for a given Arm CPU model. 108 inline ArmConfig getArmConfigForCPUArch(ARMBuildAttrs::CPUArch CPUArch) { 109 ArmConfig ArmCfg; 110 switch (CPUArch) { 111 case ARMBuildAttrs::v7: 112 case ARMBuildAttrs::v8_A: 113 ArmCfg.J1J2BranchEncoding = true; 114 ArmCfg.Stubs = Thumbv7; 115 break; 116 default: 117 DEBUG_WITH_TYPE("jitlink", { 118 dbgs() << " Warning: ARM config not defined for CPU architecture " 119 << getCPUArchName(CPUArch); 120 }); 121 break; 122 } 123 return ArmCfg; 124 } 125 126 /// Immutable pair of halfwords, Hi and Lo, with overflow check 127 struct HalfWords { 128 constexpr HalfWords() : Hi(0), Lo(0) {} 129 constexpr HalfWords(uint32_t Hi, uint32_t Lo) : Hi(Hi), Lo(Lo) { 130 assert(isUInt<16>(Hi) && "Overflow in first half-word"); 131 assert(isUInt<16>(Lo) && "Overflow in second half-word"); 132 } 133 const uint16_t Hi; // First halfword 134 const uint16_t Lo; // Second halfword 135 }; 136 137 /// Collection of named constants per fixup kind. It may contain but is not 138 /// limited to the following entries: 139 /// 140 /// Opcode - Values of the op-code bits in the instruction, with 141 /// unaffected bits nulled 142 /// OpcodeMask - Mask with all bits set that encode the op-code 143 /// ImmMask - Mask with all bits set that encode the immediate value 144 /// RegMask - Mask with all bits set that encode the register 145 /// 146 template <EdgeKind_aarch32 Kind> struct FixupInfo {}; 147 148 template <> struct FixupInfo<Thumb_Jump24> { 149 static constexpr HalfWords Opcode{0xf000, 0x8000}; 150 static constexpr HalfWords OpcodeMask{0xf800, 0x8000}; 151 static constexpr HalfWords ImmMask{0x07ff, 0x2fff}; 152 static constexpr uint16_t LoBitConditional = 0x1000; 153 }; 154 155 template <> struct FixupInfo<Thumb_Call> { 156 static constexpr HalfWords Opcode{0xf000, 0xc000}; 157 static constexpr HalfWords OpcodeMask{0xf800, 0xc000}; 158 static constexpr HalfWords ImmMask{0x07ff, 0x2fff}; 159 static constexpr uint16_t LoBitH = 0x0001; 160 static constexpr uint16_t LoBitNoBlx = 0x1000; 161 }; 162 163 template <> struct FixupInfo<Thumb_MovtAbs> { 164 static constexpr HalfWords Opcode{0xf2c0, 0x0000}; 165 static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000}; 166 static constexpr HalfWords ImmMask{0x040f, 0x70ff}; 167 static constexpr HalfWords RegMask{0x0000, 0x0f00}; 168 }; 169 170 template <> 171 struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfo<Thumb_MovtAbs> { 172 static constexpr HalfWords Opcode{0xf240, 0x0000}; 173 }; 174 175 /// Helper function to read the initial addend for Data-class relocations. 176 Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E); 177 178 /// Helper function to read the initial addend for Arm-class relocations. 179 Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E); 180 181 /// Helper function to read the initial addend for Thumb-class relocations. 182 Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E, 183 const ArmConfig &ArmCfg); 184 185 /// Read the initial addend for a REL-type relocation. It's the value encoded 186 /// in the immediate field of the fixup location by the compiler. 187 inline Expected<int64_t> readAddend(LinkGraph &G, Block &B, const Edge &E, 188 const ArmConfig &ArmCfg) { 189 Edge::Kind Kind = E.getKind(); 190 if (Kind <= LastDataRelocation) 191 return readAddendData(G, B, E); 192 193 if (Kind <= LastArmRelocation) 194 return readAddendArm(G, B, E); 195 196 if (Kind <= LastThumbRelocation) 197 return readAddendThumb(G, B, E, ArmCfg); 198 199 llvm_unreachable("Relocation must be of class Data, Arm or Thumb"); 200 } 201 202 /// Helper function to apply the fixup for Data-class relocations. 203 Error applyFixupData(LinkGraph &G, Block &B, const Edge &E); 204 205 /// Helper function to apply the fixup for Arm-class relocations. 206 Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E); 207 208 /// Helper function to apply the fixup for Thumb-class relocations. 209 Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, 210 const ArmConfig &ArmCfg); 211 212 /// Apply fixup expression for edge to block content. 213 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, 214 const ArmConfig &ArmCfg) { 215 Edge::Kind Kind = E.getKind(); 216 217 if (Kind <= LastDataRelocation) 218 return applyFixupData(G, B, E); 219 220 if (Kind <= LastArmRelocation) 221 return applyFixupArm(G, B, E); 222 223 if (Kind <= LastThumbRelocation) 224 return applyFixupThumb(G, B, E, ArmCfg); 225 226 llvm_unreachable("Relocation must be of class Data, Arm or Thumb"); 227 } 228 229 /// Stubs builder for a specific StubsFlavor 230 /// 231 /// Right now we only have one default stub kind, but we want to extend this 232 /// and allow creation of specific kinds in the future (e.g. branch range 233 /// extension or interworking). 234 /// 235 /// Let's keep it simple for the moment and not wire this through a GOT. 236 /// 237 template <StubsFlavor Flavor> 238 class StubsManager : public TableManager<StubsManager<Flavor>> { 239 public: 240 StubsManager() = default; 241 242 /// Name of the object file section that will contain all our stubs. 243 static StringRef getSectionName() { return "__llvm_jitlink_STUBS"; } 244 245 /// Implements link-graph traversal via visitExistingEdges(). 246 bool visitEdge(LinkGraph &G, Block *B, Edge &E) { 247 if (E.getTarget().isDefined()) 248 return false; 249 250 switch (E.getKind()) { 251 case Thumb_Call: 252 case Thumb_Jump24: { 253 DEBUG_WITH_TYPE("jitlink", { 254 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " 255 << B->getFixupAddress(E) << " (" << B->getAddress() << " + " 256 << formatv("{0:x}", E.getOffset()) << ")\n"; 257 }); 258 E.setTarget(this->getEntryForTarget(G, E.getTarget())); 259 return true; 260 } 261 } 262 return false; 263 } 264 265 /// Create a branch range extension stub for the class's flavor. 266 Symbol &createEntry(LinkGraph &G, Symbol &Target); 267 268 private: 269 /// Create a new node in the link-graph for the given stub template. 270 template <size_t Size> 271 Block &addStub(LinkGraph &G, const uint8_t (&Code)[Size], 272 uint64_t Alignment) { 273 ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size); 274 return G.createContentBlock(getStubsSection(G), Template, 275 orc::ExecutorAddr(), Alignment, 0); 276 } 277 278 /// Get or create the object file section that will contain all our stubs. 279 Section &getStubsSection(LinkGraph &G) { 280 if (!StubsSection) 281 StubsSection = &G.createSection(getSectionName(), 282 orc::MemProt::Read | orc::MemProt::Exec); 283 return *StubsSection; 284 } 285 286 Section *StubsSection = nullptr; 287 }; 288 289 /// Create a branch range extension stub with Thumb encoding for v7 CPUs. 290 template <> 291 Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target); 292 293 } // namespace aarch32 294 } // namespace jitlink 295 } // namespace llvm 296 297 #endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH32 298