Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:49

0001 //===------ aarch32.h - Generic JITLink arm/thumb utilities -----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Generic utilities for graphs representing arm/thumb objects.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_JITLINK_AARCH32
0014 #define LLVM_EXECUTIONENGINE_JITLINK_AARCH32
0015 
0016 #include "TableManager.h"
0017 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
0018 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
0019 #include "llvm/Support/ARMBuildAttributes.h"
0020 #include "llvm/Support/Error.h"
0021 
0022 namespace llvm {
0023 namespace jitlink {
0024 namespace aarch32 {
0025 
0026 /// Check whether the given target flags are set for this Symbol.
0027 bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags);
0028 
0029 /// JITLink-internal AArch32 fixup kinds
0030 enum EdgeKind_aarch32 : Edge::Kind {
0031 
0032   ///
0033   /// Relocations of class Data respect target endianness (unless otherwise
0034   /// specified)
0035   ///
0036   FirstDataRelocation = Edge::FirstRelocation,
0037 
0038   /// Relative 32-bit value relocation
0039   Data_Delta32 = FirstDataRelocation,
0040 
0041   /// Absolute 32-bit value relocation
0042   Data_Pointer32,
0043 
0044   /// Relative 31-bit value relocation that preserves the most-significant bit
0045   Data_PRel31,
0046 
0047   /// Create GOT entry and store offset
0048   Data_RequestGOTAndTransformToDelta32,
0049 
0050   LastDataRelocation = Data_RequestGOTAndTransformToDelta32,
0051 
0052   ///
0053   /// Relocations of class Arm (covers fixed-width 4-byte instruction subset)
0054   ///
0055   FirstArmRelocation,
0056 
0057   /// Write immediate value for unconditional PC-relative branch with link.
0058   /// We patch the instruction opcode to account for an instruction-set state
0059   /// switch: we use the bl instruction to stay in ARM and the blx instruction
0060   /// to switch to Thumb.
0061   Arm_Call = FirstArmRelocation,
0062 
0063   /// Write immediate value for conditional PC-relative branch without link.
0064   /// If the branch target is not ARM, we are forced to generate an explicit
0065   /// interworking stub.
0066   Arm_Jump24,
0067 
0068   /// Write immediate value to the lower halfword of the destination register
0069   Arm_MovwAbsNC,
0070 
0071   /// Write immediate value to the top halfword of the destination register
0072   Arm_MovtAbs,
0073 
0074   LastArmRelocation = Arm_MovtAbs,
0075 
0076   ///
0077   /// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
0078   ///
0079   FirstThumbRelocation,
0080 
0081   /// Write immediate value for unconditional PC-relative branch with link.
0082   /// We patch the instruction opcode to account for an instruction-set state
0083   /// switch: we use the bl instruction to stay in Thumb and the blx instruction
0084   /// to switch to ARM.
0085   Thumb_Call = FirstThumbRelocation,
0086 
0087   /// Write immediate value for PC-relative branch without link. The instruction
0088   /// can be made conditional by an IT block. If the branch target is not ARM,
0089   /// we are forced to generate an explicit interworking stub.
0090   Thumb_Jump24,
0091 
0092   /// Write immediate value to the lower halfword of the destination register
0093   Thumb_MovwAbsNC,
0094 
0095   /// Write immediate value to the top halfword of the destination register
0096   Thumb_MovtAbs,
0097 
0098   /// Write PC-relative immediate value to the lower halfword of the destination
0099   /// register
0100   Thumb_MovwPrelNC,
0101 
0102   /// Write PC-relative immediate value to the top halfword of the destination
0103   /// register
0104   Thumb_MovtPrel,
0105 
0106   LastThumbRelocation = Thumb_MovtPrel,
0107 
0108   /// No-op relocation
0109   None,
0110 
0111   LastRelocation = None,
0112 };
0113 
0114 /// Flags enum for AArch32-specific symbol properties
0115 enum TargetFlags_aarch32 : TargetFlagsType {
0116   ThumbSymbol = 1 << 0,
0117 };
0118 
0119 /// Human-readable name for a given CPU architecture kind
0120 const char *getCPUArchName(ARMBuildAttrs::CPUArch K);
0121 
0122 /// Get a human-readable name for the given AArch32 edge kind.
0123 const char *getEdgeKindName(Edge::Kind K);
0124 
0125 /// AArch32 uses stubs for a number of purposes, like branch range extension
0126 /// or interworking between Arm and Thumb instruction subsets.
0127 ///
0128 /// Stub implementations vary depending on CPU architecture (v4, v6, v7),
0129 /// instruction subset and branch type (absolute/PC-relative).
0130 ///
0131 /// For each kind of stub, the StubsFlavor defines one concrete form that is
0132 /// used throughout the LinkGraph.
0133 ///
0134 /// Stubs are often called "veneers" in the official docs and online.
0135 ///
0136 enum class StubsFlavor {
0137   Undefined = 0,
0138   pre_v7,
0139   v7,
0140 };
0141 
0142 /// JITLink sub-arch configuration for Arm CPU models
0143 struct ArmConfig {
0144   bool J1J2BranchEncoding = false;
0145   StubsFlavor Stubs = StubsFlavor::Undefined;
0146   // In the long term, we might want a linker switch like --target1-rel
0147   bool Target1Rel = false;
0148 };
0149 
0150 /// Obtain the sub-arch configuration for a given Arm CPU model.
0151 inline ArmConfig getArmConfigForCPUArch(ARMBuildAttrs::CPUArch CPUArch) {
0152   ArmConfig ArmCfg;
0153   if (CPUArch == ARMBuildAttrs::v7 || CPUArch >= ARMBuildAttrs::v7E_M) {
0154     ArmCfg.J1J2BranchEncoding = true;
0155     ArmCfg.Stubs = StubsFlavor::v7;
0156   } else {
0157     ArmCfg.J1J2BranchEncoding = false;
0158     ArmCfg.Stubs = StubsFlavor::pre_v7;
0159   }
0160   return ArmCfg;
0161 }
0162 
0163 /// Immutable pair of halfwords, Hi and Lo, with overflow check
0164 struct HalfWords {
0165   constexpr HalfWords() : Hi(0), Lo(0) {}
0166   constexpr HalfWords(uint32_t Hi, uint32_t Lo) : Hi(Hi), Lo(Lo) {
0167     assert(isUInt<16>(Hi) && "Overflow in first half-word");
0168     assert(isUInt<16>(Lo) && "Overflow in second half-word");
0169   }
0170   const uint16_t Hi; // First halfword
0171   const uint16_t Lo; // Second halfword
0172 };
0173 
0174 /// FixupInfo base class is required for dynamic lookups.
0175 struct FixupInfoBase {
0176   static const FixupInfoBase *getDynFixupInfo(Edge::Kind K);
0177   virtual ~FixupInfoBase() {}
0178 };
0179 
0180 /// FixupInfo checks for Arm edge kinds work on 32-bit words
0181 struct FixupInfoArm : public FixupInfoBase {
0182   bool (*checkOpcode)(uint32_t Wd) = nullptr;
0183 };
0184 
0185 /// FixupInfo check for Thumb32 edge kinds work on a pair of 16-bit halfwords
0186 struct FixupInfoThumb : public FixupInfoBase {
0187   bool (*checkOpcode)(uint16_t Hi, uint16_t Lo) = nullptr;
0188 };
0189 
0190 /// Collection of named constants per fixup kind
0191 ///
0192 /// Mandatory entries:
0193 ///   Opcode      - Values of the op-code bits in the instruction, with
0194 ///                 unaffected bits nulled
0195 ///   OpcodeMask  - Mask with all bits set that encode the op-code
0196 ///
0197 /// Other common entries:
0198 ///   ImmMask     - Mask with all bits set that encode the immediate value
0199 ///   RegMask     - Mask with all bits set that encode the register
0200 ///
0201 /// Specializations can add further custom fields without restrictions.
0202 ///
0203 template <EdgeKind_aarch32 Kind> struct FixupInfo {};
0204 
0205 struct FixupInfoArmBranch : public FixupInfoArm {
0206   static constexpr uint32_t Opcode = 0x0a000000;
0207   static constexpr uint32_t ImmMask = 0x00ffffff;
0208 };
0209 
0210 template <> struct FixupInfo<Arm_Jump24> : public FixupInfoArmBranch {
0211   static constexpr uint32_t OpcodeMask = 0x0f000000;
0212 };
0213 
0214 template <> struct FixupInfo<Arm_Call> : public FixupInfoArmBranch {
0215   static constexpr uint32_t OpcodeMask = 0x0e000000;
0216   static constexpr uint32_t CondMask = 0xe0000000; // excluding BLX bit
0217   static constexpr uint32_t Unconditional = 0xe0000000;
0218   static constexpr uint32_t BitH = 0x01000000;
0219   static constexpr uint32_t BitBlx = 0x10000000;
0220 };
0221 
0222 struct FixupInfoArmMov : public FixupInfoArm {
0223   static constexpr uint32_t OpcodeMask = 0x0ff00000;
0224   static constexpr uint32_t ImmMask = 0x000f0fff;
0225   static constexpr uint32_t RegMask = 0x0000f000;
0226 };
0227 
0228 template <> struct FixupInfo<Arm_MovtAbs> : public FixupInfoArmMov {
0229   static constexpr uint32_t Opcode = 0x03400000;
0230 };
0231 
0232 template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfoArmMov {
0233   static constexpr uint32_t Opcode = 0x03000000;
0234 };
0235 
0236 template <> struct FixupInfo<Thumb_Jump24> : public FixupInfoThumb {
0237   static constexpr HalfWords Opcode{0xf000, 0x9000};
0238   static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
0239   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
0240 };
0241 
0242 template <> struct FixupInfo<Thumb_Call> : public FixupInfoThumb {
0243   static constexpr HalfWords Opcode{0xf000, 0xc000};
0244   static constexpr HalfWords OpcodeMask{0xf800, 0xc000};
0245   static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
0246   static constexpr uint16_t LoBitH = 0x0001;
0247   static constexpr uint16_t LoBitNoBlx = 0x1000;
0248 };
0249 
0250 struct FixupInfoThumbMov : public FixupInfoThumb {
0251   static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000};
0252   static constexpr HalfWords ImmMask{0x040f, 0x70ff};
0253   static constexpr HalfWords RegMask{0x0000, 0x0f00};
0254 };
0255 
0256 template <> struct FixupInfo<Thumb_MovtAbs> : public FixupInfoThumbMov {
0257   static constexpr HalfWords Opcode{0xf2c0, 0x0000};
0258 };
0259 
0260 template <> struct FixupInfo<Thumb_MovtPrel> : public FixupInfoThumbMov {
0261   static constexpr HalfWords Opcode{0xf2c0, 0x0000};
0262 };
0263 
0264 template <> struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfoThumbMov {
0265   static constexpr HalfWords Opcode{0xf240, 0x0000};
0266 };
0267 
0268 template <> struct FixupInfo<Thumb_MovwPrelNC> : public FixupInfoThumbMov {
0269   static constexpr HalfWords Opcode{0xf240, 0x0000};
0270 };
0271 
0272 /// Helper function to read the initial addend for Data-class relocations.
0273 Expected<int64_t> readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset,
0274                                  Edge::Kind Kind);
0275 
0276 /// Helper function to read the initial addend for Arm-class relocations.
0277 Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset,
0278                                 Edge::Kind Kind);
0279 
0280 /// Helper function to read the initial addend for Thumb-class relocations.
0281 Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset,
0282                                   Edge::Kind Kind, const ArmConfig &ArmCfg);
0283 
0284 /// Read the initial addend for a REL-type relocation. It's the value encoded
0285 /// in the immediate field of the fixup location by the compiler.
0286 inline Expected<int64_t> readAddend(LinkGraph &G, Block &B,
0287                                     Edge::OffsetT Offset, Edge::Kind Kind,
0288                                     const ArmConfig &ArmCfg) {
0289   if (Kind <= LastDataRelocation)
0290     return readAddendData(G, B, Offset, Kind);
0291 
0292   if (Kind <= LastArmRelocation)
0293     return readAddendArm(G, B, Offset, Kind);
0294 
0295   if (Kind <= LastThumbRelocation)
0296     return readAddendThumb(G, B, Offset, Kind, ArmCfg);
0297 
0298   assert(Kind == None && "Not associated with a relocation class");
0299   return 0;
0300 }
0301 
0302 /// Helper function to apply the fixup for Data-class relocations.
0303 Error applyFixupData(LinkGraph &G, Block &B, const Edge &E);
0304 
0305 /// Helper function to apply the fixup for Arm-class relocations.
0306 Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E);
0307 
0308 /// Helper function to apply the fixup for Thumb-class relocations.
0309 Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
0310                       const ArmConfig &ArmCfg);
0311 
0312 /// Apply fixup expression for edge to block content.
0313 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
0314                         const ArmConfig &ArmCfg) {
0315   Edge::Kind Kind = E.getKind();
0316 
0317   if (Kind <= LastDataRelocation)
0318     return applyFixupData(G, B, E);
0319 
0320   if (Kind <= LastArmRelocation)
0321     return applyFixupArm(G, B, E);
0322 
0323   if (Kind <= LastThumbRelocation)
0324     return applyFixupThumb(G, B, E, ArmCfg);
0325 
0326   assert(Kind == None && "Not associated with a relocation class");
0327   return Error::success();
0328 }
0329 
0330 /// Populate a Global Offset Table from edges that request it.
0331 class GOTBuilder : public TableManager<GOTBuilder> {
0332 public:
0333   static StringRef getSectionName() { return "$__GOT"; }
0334 
0335   bool visitEdge(LinkGraph &G, Block *B, Edge &E);
0336   Symbol &createEntry(LinkGraph &G, Symbol &Target);
0337 
0338 private:
0339   Section *GOTSection = nullptr;
0340 };
0341 
0342 /// Stubs builder emits non-position-independent Arm stubs for pre-v7 CPUs.
0343 /// These architectures have no MovT/MovW instructions and don't support Thumb2.
0344 /// BL is the only Thumb instruction that can generate stubs and they can always
0345 /// be transformed into BLX.
0346 class StubsManager_prev7 {
0347 public:
0348   StubsManager_prev7() = default;
0349 
0350   /// Name of the object file section that will contain all our stubs.
0351   static StringRef getSectionName() {
0352     return "__llvm_jitlink_aarch32_STUBS_prev7";
0353   }
0354 
0355   /// Implements link-graph traversal via visitExistingEdges()
0356   bool visitEdge(LinkGraph &G, Block *B, Edge &E);
0357 
0358 private:
0359   // Each stub uses a single block that can have 2 entryponts, one for Arm and
0360   // one for Thumb
0361   struct StubMapEntry {
0362     Block *B = nullptr;
0363     Symbol *ArmEntry = nullptr;
0364     Symbol *ThumbEntry = nullptr;
0365   };
0366 
0367   std::pair<StubMapEntry *, bool> getStubMapSlot(StringRef Name) {
0368     auto &&[Stubs, NewStub] = StubMap.try_emplace(Name);
0369     return std::make_pair(&Stubs->second, NewStub);
0370   }
0371 
0372   Symbol *getOrCreateSlotEntrypoint(LinkGraph &G, StubMapEntry &Slot,
0373                                     bool Thumb);
0374 
0375   DenseMap<StringRef, StubMapEntry> StubMap;
0376   Section *StubsSection = nullptr;
0377 };
0378 
0379 /// Stubs builder for v7 emits non-position-independent Arm and Thumb stubs.
0380 class StubsManager_v7 {
0381 public:
0382   StubsManager_v7() = default;
0383 
0384   /// Name of the object file section that will contain all our stubs.
0385   static StringRef getSectionName() {
0386     return "__llvm_jitlink_aarch32_STUBS_v7";
0387   }
0388 
0389   /// Implements link-graph traversal via visitExistingEdges().
0390   bool visitEdge(LinkGraph &G, Block *B, Edge &E);
0391 
0392 private:
0393   // Two slots per external: Arm and Thumb
0394   using StubMapEntry = std::tuple<Symbol *, Symbol *>;
0395 
0396   Symbol *&getStubSymbolSlot(StringRef Name, bool Thumb) {
0397     StubMapEntry &Stubs = StubMap[Name];
0398     if (Thumb)
0399       return std::get<1>(Stubs);
0400     return std::get<0>(Stubs);
0401   }
0402 
0403   DenseMap<StringRef, StubMapEntry> StubMap;
0404   Section *StubsSection = nullptr;
0405 };
0406 
0407 } // namespace aarch32
0408 } // namespace jitlink
0409 } // namespace llvm
0410 
0411 #endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH32