diff options
Diffstat (limited to 'llvm/include/llvm/ExecutionEngine/JITLink')
-rw-r--r-- | llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h | 162 |
1 files changed, 90 insertions, 72 deletions
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h index f346cfb2a931..eda6feb441e6 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h @@ -41,7 +41,13 @@ enum EdgeKind_aarch32 : Edge::Kind { /// Absolute 32-bit value relocation Data_Pointer32, - LastDataRelocation = Data_Pointer32, + /// Relative 31-bit value relocation that preserves the most-significant bit + Data_PRel31, + + /// Create GOT entry and store offset + Data_RequestGOTAndTransformToDelta32, + + LastDataRelocation = Data_RequestGOTAndTransformToDelta32, /// /// Relocations of class Arm (covers fixed-width 4-byte instruction subset) @@ -98,7 +104,11 @@ enum EdgeKind_aarch32 : Edge::Kind { Thumb_MovtPrel, LastThumbRelocation = Thumb_MovtPrel, - LastRelocation = LastThumbRelocation, + + /// No-op relocation + None, + + LastRelocation = None, }; /// Flags enum for AArch32-specific symbol properties @@ -123,32 +133,29 @@ const char *getEdgeKindName(Edge::Kind K); /// /// Stubs are often called "veneers" in the official docs and online. /// -enum StubsFlavor { - Unsupported = 0, - Thumbv7, +enum class StubsFlavor { + Undefined = 0, + pre_v7, + v7, }; /// JITLink sub-arch configuration for Arm CPU models struct ArmConfig { bool J1J2BranchEncoding = false; - StubsFlavor Stubs = Unsupported; + StubsFlavor Stubs = StubsFlavor::Undefined; + // In the long term, we might want a linker switch like --target1-rel + bool Target1Rel = false; }; /// Obtain the sub-arch configuration for a given Arm CPU model. inline ArmConfig getArmConfigForCPUArch(ARMBuildAttrs::CPUArch CPUArch) { ArmConfig ArmCfg; - switch (CPUArch) { - case ARMBuildAttrs::v7: - case ARMBuildAttrs::v8_A: + if (CPUArch == ARMBuildAttrs::v7 || CPUArch >= ARMBuildAttrs::v7E_M) { ArmCfg.J1J2BranchEncoding = true; - ArmCfg.Stubs = Thumbv7; - break; - default: - DEBUG_WITH_TYPE("jitlink", { - dbgs() << " Warning: ARM config not defined for CPU architecture " - << getCPUArchName(CPUArch); - }); - break; + ArmCfg.Stubs = StubsFlavor::v7; + } else { + ArmCfg.J1J2BranchEncoding = false; + ArmCfg.Stubs = StubsFlavor::pre_v7; } return ArmCfg; } @@ -288,7 +295,8 @@ inline Expected<int64_t> readAddend(LinkGraph &G, Block &B, if (Kind <= LastThumbRelocation) return readAddendThumb(G, B, Offset, Kind, ArmCfg); - llvm_unreachable("Relocation must be of class Data, Arm or Thumb"); + assert(Kind == None && "Not associated with a relocation class"); + return 0; } /// Helper function to apply the fixup for Data-class relocations. @@ -315,76 +323,86 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, if (Kind <= LastThumbRelocation) return applyFixupThumb(G, B, E, ArmCfg); - llvm_unreachable("Relocation must be of class Data, Arm or Thumb"); + assert(Kind == None && "Not associated with a relocation class"); + return Error::success(); } -/// Stubs builder for a specific StubsFlavor -/// -/// Right now we only have one default stub kind, but we want to extend this -/// and allow creation of specific kinds in the future (e.g. branch range -/// extension or interworking). -/// -/// Let's keep it simple for the moment and not wire this through a GOT. -/// -template <StubsFlavor Flavor> -class StubsManager : public TableManager<StubsManager<Flavor>> { +/// Populate a Global Offset Table from edges that request it. +class GOTBuilder : public TableManager<GOTBuilder> { public: - StubsManager() = default; + static StringRef getSectionName() { return "$__GOT"; } - /// Name of the object file section that will contain all our stubs. - static StringRef getSectionName(); + bool visitEdge(LinkGraph &G, Block *B, Edge &E); + Symbol &createEntry(LinkGraph &G, Symbol &Target); - /// Implements link-graph traversal via visitExistingEdges(). - bool visitEdge(LinkGraph &G, Block *B, Edge &E) { - if (E.getTarget().isDefined()) - return false; - - switch (E.getKind()) { - case Thumb_Call: - case Thumb_Jump24: { - DEBUG_WITH_TYPE("jitlink", { - dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " - << B->getFixupAddress(E) << " (" << B->getAddress() << " + " - << formatv("{0:x}", E.getOffset()) << ")\n"; - }); - E.setTarget(this->getEntryForTarget(G, E.getTarget())); - return true; - } - } - return false; +private: + Section *GOTSection = nullptr; +}; + +/// Stubs builder emits non-position-independent Arm stubs for pre-v7 CPUs. +/// These architectures have no MovT/MovW instructions and don't support Thumb2. +/// BL is the only Thumb instruction that can generate stubs and they can always +/// be transformed into BLX. +class StubsManager_prev7 { +public: + StubsManager_prev7() = default; + + /// Name of the object file section that will contain all our stubs. + static StringRef getSectionName() { + return "__llvm_jitlink_aarch32_STUBS_prev7"; } - /// Create a branch range extension stub for the class's flavor. - Symbol &createEntry(LinkGraph &G, Symbol &Target); + /// Implements link-graph traversal via visitExistingEdges() + bool visitEdge(LinkGraph &G, Block *B, Edge &E); private: - /// Create a new node in the link-graph for the given stub template. - template <size_t Size> - Block &addStub(LinkGraph &G, const uint8_t (&Code)[Size], - uint64_t Alignment) { - ArrayRef<char> Template(reinterpret_cast<const char *>(Code), Size); - return G.createContentBlock(getStubsSection(G), Template, - orc::ExecutorAddr(), Alignment, 0); + // Each stub uses a single block that can have 2 entryponts, one for Arm and + // one for Thumb + struct StubMapEntry { + Block *B = nullptr; + Symbol *ArmEntry = nullptr; + Symbol *ThumbEntry = nullptr; + }; + + std::pair<StubMapEntry *, bool> getStubMapSlot(StringRef Name) { + auto &&[Stubs, NewStub] = StubMap.try_emplace(Name); + return std::make_pair(&Stubs->second, NewStub); } - /// Get or create the object file section that will contain all our stubs. - Section &getStubsSection(LinkGraph &G) { - if (!StubsSection) - StubsSection = &G.createSection(getSectionName(), - orc::MemProt::Read | orc::MemProt::Exec); - return *StubsSection; - } + Symbol *getOrCreateSlotEntrypoint(LinkGraph &G, StubMapEntry &Slot, + bool Thumb); + DenseMap<StringRef, StubMapEntry> StubMap; Section *StubsSection = nullptr; }; -/// Create a branch range extension stub with Thumb encoding for v7 CPUs. -template <> -Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target); +/// Stubs builder for v7 emits non-position-independent Arm and Thumb stubs. +class StubsManager_v7 { +public: + StubsManager_v7() = default; + + /// Name of the object file section that will contain all our stubs. + static StringRef getSectionName() { + return "__llvm_jitlink_aarch32_STUBS_v7"; + } -template <> inline StringRef StubsManager<Thumbv7>::getSectionName() { - return "__llvm_jitlink_aarch32_STUBS_Thumbv7"; -} + /// Implements link-graph traversal via visitExistingEdges(). + bool visitEdge(LinkGraph &G, Block *B, Edge &E); + +private: + // Two slots per external: Arm and Thumb + using StubMapEntry = std::tuple<Symbol *, Symbol *>; + + Symbol *&getStubSymbolSlot(StringRef Name, bool Thumb) { + StubMapEntry &Stubs = StubMap.try_emplace(Name).first->second; + if (Thumb) + return std::get<1>(Stubs); + return std::get<0>(Stubs); + } + + DenseMap<StringRef, StubMapEntry> StubMap; + Section *StubsSection = nullptr; +}; } // namespace aarch32 } // namespace jitlink |