LLVM 18.0.0git
aarch32.h
Go to the documentation of this file.
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"
20#include "llvm/Support/Error.h"
21
22namespace llvm {
23namespace jitlink {
24namespace aarch32 {
25
26/// Check whether the given target flags are set for this Symbol.
28
29/// JITLink-internal AArch32 fixup kinds
31
32 ///
33 /// Relocations of class Data respect target endianness (unless otherwise
34 /// specified)
35 ///
37
38 /// Relative 32-bit value relocation
40
41 /// Absolute 32-bit value relocation
43
45
46 ///
47 /// Relocations of class Arm (covers fixed-width 4-byte instruction subset)
48 ///
50
51 /// Write immediate value for unconditional PC-relative branch with link.
52 /// We patch the instruction opcode to account for an instruction-set state
53 /// switch: we use the bl instruction to stay in ARM and the blx instruction
54 /// to switch to Thumb.
56
57 /// Write immediate value for conditional PC-relative branch without link.
58 /// If the branch target is not ARM, we are forced to generate an explicit
59 /// interworking stub.
61
62 /// Write immediate value to the lower halfword of the destination register
64
65 /// Write immediate value to the top halfword of the destination register
67
69
70 ///
71 /// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
72 ///
74
75 /// Write immediate value for unconditional PC-relative branch with link.
76 /// We patch the instruction opcode to account for an instruction-set state
77 /// switch: we use the bl instruction to stay in Thumb and the blx instruction
78 /// to switch to ARM.
80
81 /// Write immediate value for PC-relative branch without link. The instruction
82 /// can be made conditional by an IT block. If the branch target is not ARM,
83 /// we are forced to generate an explicit interworking stub.
85
86 /// Write immediate value to the lower halfword of the destination register
88
89 /// Write immediate value to the top halfword of the destination register
91
93};
94
95/// Flags enum for AArch32-specific symbol properties
97 ThumbSymbol = 1 << 0,
98};
99
100/// Human-readable name for a given CPU architecture kind
102
103/// Get a human-readable name for the given AArch32 edge kind.
104const char *getEdgeKindName(Edge::Kind K);
105
106/// AArch32 uses stubs for a number of purposes, like branch range extension
107/// or interworking between Arm and Thumb instruction subsets.
108///
109/// Stub implementations vary depending on CPU architecture (v4, v6, v7),
110/// instruction subset and branch type (absolute/PC-relative).
111///
112/// For each kind of stub, the StubsFlavor defines one concrete form that is
113/// used throughout the LinkGraph.
114///
115/// Stubs are often called "veneers" in the official docs and online.
116///
120};
121
122/// JITLink sub-arch configuration for Arm CPU models
123struct ArmConfig {
124 bool J1J2BranchEncoding = false;
126};
127
128/// Obtain the sub-arch configuration for a given Arm CPU model.
130 ArmConfig ArmCfg;
131 switch (CPUArch) {
134 ArmCfg.J1J2BranchEncoding = true;
135 ArmCfg.Stubs = Thumbv7;
136 break;
137 default:
138 DEBUG_WITH_TYPE("jitlink", {
139 dbgs() << " Warning: ARM config not defined for CPU architecture "
140 << getCPUArchName(CPUArch);
141 });
142 break;
143 }
144 return ArmCfg;
145}
146
147/// Immutable pair of halfwords, Hi and Lo, with overflow check
148struct HalfWords {
149 constexpr HalfWords() : Hi(0), Lo(0) {}
150 constexpr HalfWords(uint32_t Hi, uint32_t Lo) : Hi(Hi), Lo(Lo) {
151 assert(isUInt<16>(Hi) && "Overflow in first half-word");
152 assert(isUInt<16>(Lo) && "Overflow in second half-word");
153 }
154 const uint16_t Hi; // First halfword
155 const uint16_t Lo; // Second halfword
156};
157
158/// Collection of named constants per fixup kind. It may contain but is not
159/// limited to the following entries:
160///
161/// Opcode - Values of the op-code bits in the instruction, with
162/// unaffected bits nulled
163/// OpcodeMask - Mask with all bits set that encode the op-code
164/// ImmMask - Mask with all bits set that encode the immediate value
165/// RegMask - Mask with all bits set that encode the register
166///
167template <EdgeKind_aarch32 Kind> struct FixupInfo {};
168
169template <> struct FixupInfo<Arm_Jump24> {
170 static constexpr uint32_t Opcode = 0x0a000000;
171 static constexpr uint32_t OpcodeMask = 0x0f000000;
172 static constexpr uint32_t ImmMask = 0x00ffffff;
173 static constexpr uint32_t Unconditional = 0xe0000000;
174 static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
175};
176
177template <> struct FixupInfo<Arm_Call> : public FixupInfo<Arm_Jump24> {
178 static constexpr uint32_t OpcodeMask = 0x0e000000;
179 static constexpr uint32_t BitH = 0x01000000;
180 static constexpr uint32_t BitBlx = 0x10000000;
181};
182
183template <> struct FixupInfo<Arm_MovtAbs> {
184 static constexpr uint32_t Opcode = 0x03400000;
185 static constexpr uint32_t OpcodeMask = 0x0ff00000;
186 static constexpr uint32_t ImmMask = 0x000f0fff;
187 static constexpr uint32_t RegMask = 0x0000f000;
188};
189
190template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfo<Arm_MovtAbs> {
191 static constexpr uint32_t Opcode = 0x03000000;
192};
193
194template <> struct FixupInfo<Thumb_Jump24> {
195 static constexpr HalfWords Opcode{0xf000, 0x8000};
196 static constexpr HalfWords OpcodeMask{0xf800, 0x8000};
197 static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
198};
199
200template <> struct FixupInfo<Thumb_Call> {
201 static constexpr HalfWords Opcode{0xf000, 0xc000};
202 static constexpr HalfWords OpcodeMask{0xf800, 0xc000};
203 static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
204 static constexpr uint16_t LoBitH = 0x0001;
205 static constexpr uint16_t LoBitNoBlx = 0x1000;
206};
207
208template <> struct FixupInfo<Thumb_MovtAbs> {
209 static constexpr HalfWords Opcode{0xf2c0, 0x0000};
210 static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
211 static constexpr HalfWords ImmMask{0x040f, 0x70ff};
212 static constexpr HalfWords RegMask{0x0000, 0x0f00};
213};
214
215template <>
216struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfo<Thumb_MovtAbs> {
217 static constexpr HalfWords Opcode{0xf240, 0x0000};
218};
219
220/// Helper function to read the initial addend for Data-class relocations.
222
223/// Helper function to read the initial addend for Arm-class relocations.
225
226/// Helper function to read the initial addend for Thumb-class relocations.
228 const ArmConfig &ArmCfg);
229
230/// Read the initial addend for a REL-type relocation. It's the value encoded
231/// in the immediate field of the fixup location by the compiler.
233 const ArmConfig &ArmCfg) {
234 Edge::Kind Kind = E.getKind();
235 if (Kind <= LastDataRelocation)
236 return readAddendData(G, B, E);
237
238 if (Kind <= LastArmRelocation)
239 return readAddendArm(G, B, E);
240
241 if (Kind <= LastThumbRelocation)
242 return readAddendThumb(G, B, E, ArmCfg);
243
244 llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
245}
246
247/// Helper function to apply the fixup for Data-class relocations.
249
250/// Helper function to apply the fixup for Arm-class relocations.
252
253/// Helper function to apply the fixup for Thumb-class relocations.
255 const ArmConfig &ArmCfg);
256
257/// Apply fixup expression for edge to block content.
259 const ArmConfig &ArmCfg) {
260 Edge::Kind Kind = E.getKind();
261
262 if (Kind <= LastDataRelocation)
263 return applyFixupData(G, B, E);
264
265 if (Kind <= LastArmRelocation)
266 return applyFixupArm(G, B, E);
267
268 if (Kind <= LastThumbRelocation)
269 return applyFixupThumb(G, B, E, ArmCfg);
270
271 llvm_unreachable("Relocation must be of class Data, Arm or Thumb");
272}
273
274/// Stubs builder for a specific StubsFlavor
275///
276/// Right now we only have one default stub kind, but we want to extend this
277/// and allow creation of specific kinds in the future (e.g. branch range
278/// extension or interworking).
279///
280/// Let's keep it simple for the moment and not wire this through a GOT.
281///
282template <StubsFlavor Flavor>
283class StubsManager : public TableManager<StubsManager<Flavor>> {
284public:
285 StubsManager() = default;
286
287 /// Name of the object file section that will contain all our stubs.
288 static StringRef getSectionName() { return "__llvm_jitlink_STUBS"; }
289
290 /// Implements link-graph traversal via visitExistingEdges().
292 if (E.getTarget().isDefined())
293 return false;
294
295 switch (E.getKind()) {
296 case Thumb_Call:
297 case Thumb_Jump24: {
298 DEBUG_WITH_TYPE("jitlink", {
299 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
300 << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
301 << formatv("{0:x}", E.getOffset()) << ")\n";
302 });
303 E.setTarget(this->getEntryForTarget(G, E.getTarget()));
304 return true;
305 }
306 }
307 return false;
308 }
309
310 /// Create a branch range extension stub for the class's flavor.
312
313private:
314 /// Create a new node in the link-graph for the given stub template.
315 template <size_t Size>
316 Block &addStub(LinkGraph &G, const uint8_t (&Code)[Size],
317 uint64_t Alignment) {
318 ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size);
319 return G.createContentBlock(getStubsSection(G), Template,
320 orc::ExecutorAddr(), Alignment, 0);
321 }
322
323 /// Get or create the object file section that will contain all our stubs.
324 Section &getStubsSection(LinkGraph &G) {
325 if (!StubsSection)
326 StubsSection = &G.createSection(getSectionName(),
328 return *StubsSection;
329 }
330
331 Section *StubsSection = nullptr;
332};
333
334/// Create a branch range extension stub with Thumb encoding for v7 CPUs.
335template <>
337
338} // namespace aarch32
339} // namespace jitlink
340} // namespace llvm
341
342#endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH32
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define DEBUG_WITH_TYPE(TYPE, X)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
Definition: Debug.h:64
uint64_t Size
Symbol * Sym
Definition: ELF_riscv.cpp:468
#define G(x, y, z)
Definition: MD5.cpp:56
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
Tagged union holding either a T or a Error.
Definition: Error.h:474
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Target - Wrapper for Target specific information.
Represents an address in the executor process.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163