diff options
-rw-r--r-- | llvm/include/llvm/ExecutionEngine/JITLink/ELF_aarch32.h | 38 | ||||
-rw-r--r-- | llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h | 293 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt | 2 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/ELF.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h | 21 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp | 299 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/aarch32.cpp | 514 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp | 6 | ||||
-rw-r--r-- | llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumbv7_printf.s | 46 | ||||
-rw-r--r-- | llvm/test/ExecutionEngine/JITLink/AArch32/lit.local.cfg | 2 | ||||
-rw-r--r-- | llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp | 200 | ||||
-rw-r--r-- | llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt | 1 |
12 files changed, 1 insertions, 1430 deletions
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_aarch32.h deleted file mode 100644 index 25d1c3a..0000000 --- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_aarch32.h +++ /dev/null @@ -1,38 +0,0 @@ -//===---- ELF_aarch32.h - JIT link functions for arm/thumb -----*- C++ -*--===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// jit-link functions for ELF/aarch32. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_JITLINK_ELF_AARCH32 -#define LLVM_EXECUTIONENGINE_JITLINK_ELF_AARCH32 - -#include "llvm/ExecutionEngine/JITLink/JITLink.h" -#include "llvm/ExecutionEngine/JITLink/aarch32.h" - -namespace llvm { -namespace jitlink { - -/// Create a LinkGraph from an ELF/arm relocatable object -/// -/// Note: The graph does not take ownership of the underlying buffer, nor copy -/// its contents. The caller is responsible for ensuring that the object buffer -/// outlives the graph. -Expected<std::unique_ptr<LinkGraph>> -createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer); - -/// jit-link the given object buffer, which must be an ELF arm/thumb object -/// file. -void link_ELF_aarch32(std::unique_ptr<LinkGraph> G, - std::unique_ptr<JITLinkContext> Ctx); - -} // end namespace jitlink -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_JITLINK_ELF_AARCH32 diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h deleted file mode 100644 index 8488b10..0000000 --- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h +++ /dev/null @@ -1,293 +0,0 @@ -//===------ aarch32.h - Generic JITLink arm/thumb utilities -----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Generic utilities for graphs representing arm/thumb objects. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_JITLINK_AARCH32 -#define LLVM_EXECUTIONENGINE_JITLINK_AARCH32 - -#include "TableManager.h" -#include "llvm/ExecutionEngine/JITLink/JITLink.h" -#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" -#include "llvm/Support/ARMBuildAttributes.h" -#include "llvm/Support/Error.h" - -namespace llvm { -namespace jitlink { -namespace aarch32 { - -/// JITLink-internal AArch32 fixup kinds -enum EdgeKind_aarch32 : Edge::Kind { - - /// - /// Relocations of class Data - /// - FirstDataRelocation = Edge::FirstRelocation, - - /// Plain 32-bit value relocation in target endianness - Data_Delta32 = FirstDataRelocation, - - LastDataRelocation = Data_Delta32, - - /// - /// Relocations of class Arm (covers fixed-width 4-byte instruction subset) - /// - FirstArmRelocation, - - /// TODO: Arm_Call is here only as a placeholder for now. - Arm_Call = FirstArmRelocation, - - LastArmRelocation = Arm_Call, - - /// - /// Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset) - /// - FirstThumbRelocation, - - /// Write immediate value for PC-relative branch with link (can bridge between - /// Arm and Thumb). - Thumb_Call = FirstThumbRelocation, - - /// Write immediate value for (unconditional) PC-relative branch without link. - Thumb_Jump24, - - /// Write immediate value to the lower halfword of the destination register - Thumb_MovwAbsNC, - - /// Write immediate value to the top halfword of the destination register - Thumb_MovtAbs, - - LastThumbRelocation = Thumb_MovtAbs, -}; - -/// Flags enum for AArch32-specific symbol properties -enum TargetFlags_aarch32 : TargetFlagsType { - ThumbSymbol = 1 << 0, -}; - -/// Human-readable name for a given CPU architecture kind -const char *getCPUArchName(ARMBuildAttrs::CPUArch K); - -/// Get a human-readable name for the given AArch32 edge kind. -const char *getEdgeKindName(Edge::Kind K); - -/// AArch32 uses stubs for a number of purposes, like branch range extension -/// or interworking between Arm and Thumb instruction subsets. -/// -/// Stub implementations vary depending on CPU architecture (v4, v6, v7), -/// instruction subset and branch type (absolute/PC-relative). -/// -/// For each kind of stub, the StubsFlavor defines one concrete form that is -/// used throughout the LinkGraph. -/// -/// Stubs are often called "veneers" in the official docs and online. -/// -enum StubsFlavor { - Unsupported = 0, - Thumbv7, -}; - -/// JITLink sub-arch configuration for Arm CPU models -struct ArmConfig { - bool J1J2BranchEncoding = false; - StubsFlavor Stubs = Unsupported; -}; - -/// 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: - ArmCfg.J1J2BranchEncoding = true; - ArmCfg.Stubs = Thumbv7; - break; - default: - DEBUG_WITH_TYPE("jitlink", { - dbgs() << " Warning: ARM config not defined for CPU architecture " - << getCPUArchName(CPUArch); - }); - break; - } - return ArmCfg; -} - -/// Immutable pair of halfwords, Hi and Lo, with overflow check -struct HalfWords { - constexpr HalfWords() : Hi(0), Lo(0) {} - constexpr HalfWords(uint32_t Hi, uint32_t Lo) : Hi(Hi), Lo(Lo) { - assert(isUInt<16>(Hi) && "Overflow in first half-word"); - assert(isUInt<16>(Lo) && "Overflow in second half-word"); - } - const uint16_t Hi; // First halfword - const uint16_t Lo; // Second halfword -}; - -/// Collection of named constants per fixup kind. It may contain but is not -/// limited to the following entries: -/// -/// Opcode - Values of the op-code bits in the instruction, with -/// unaffected bits nulled -/// OpcodeMask - Mask with all bits set that encode the op-code -/// ImmMask - Mask with all bits set that encode the immediate value -/// RegMask - Mask with all bits set that encode the register -/// -template <EdgeKind_aarch32 Kind> struct FixupInfo {}; - -template <> struct FixupInfo<Thumb_Jump24> { - static constexpr HalfWords Opcode{0xf000, 0x8000}; - static constexpr HalfWords OpcodeMask{0xf800, 0x8000}; - static constexpr HalfWords ImmMask{0x07ff, 0x2fff}; - static constexpr uint16_t LoBitConditional = 0x1000; -}; - -template <> struct FixupInfo<Thumb_Call> { - static constexpr HalfWords Opcode{0xf000, 0xc000}; - static constexpr HalfWords OpcodeMask{0xf800, 0xc000}; - static constexpr HalfWords ImmMask{0x07ff, 0x2fff}; - static constexpr uint16_t LoBitH = 0x0001; - static constexpr uint16_t LoBitNoBlx = 0x1000; -}; - -template <> struct FixupInfo<Thumb_MovtAbs> { - static constexpr HalfWords Opcode{0xf2c0, 0x0000}; - static constexpr HalfWords OpcodeMask{0xfbf0, 0x8000}; - static constexpr HalfWords ImmMask{0x040f, 0x70ff}; - static constexpr HalfWords RegMask{0x0000, 0x0f00}; -}; - -template <> -struct FixupInfo<Thumb_MovwAbsNC> : public FixupInfo<Thumb_MovtAbs> { - static constexpr HalfWords Opcode{0xf240, 0x0000}; -}; - -/// Helper function to read the initial addend for Data-class relocations. -Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E); - -/// Helper function to read the initial addend for Arm-class relocations. -Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E); - -/// Helper function to read the initial addend for Thumb-class relocations. -Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E, - const ArmConfig &ArmCfg); - -/// Read the initial addend for a REL-type relocation. It's the value encoded -/// in the immediate field of the fixup location by the compiler. -inline Expected<int64_t> readAddend(LinkGraph &G, Block &B, const Edge &E, - const ArmConfig &ArmCfg) { - Edge::Kind Kind = E.getKind(); - if (Kind <= LastDataRelocation) - return readAddendData(G, B, E); - - if (Kind <= LastArmRelocation) - return readAddendArm(G, B, E); - - if (Kind <= LastThumbRelocation) - return readAddendThumb(G, B, E, ArmCfg); - - llvm_unreachable("Relocation must be of class Data, Arm or Thumb"); -} - -/// Helper function to apply the fixup for Data-class relocations. -Error applyFixupData(LinkGraph &G, Block &B, const Edge &E); - -/// Helper function to apply the fixup for Arm-class relocations. -Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E); - -/// Helper function to apply the fixup for Thumb-class relocations. -Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, - const ArmConfig &ArmCfg); - -/// Apply fixup expression for edge to block content. -inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, - const ArmConfig &ArmCfg) { - Edge::Kind Kind = E.getKind(); - - if (Kind <= LastDataRelocation) - return applyFixupData(G, B, E); - - if (Kind <= LastArmRelocation) - return applyFixupArm(G, B, E); - - if (Kind <= LastThumbRelocation) - return applyFixupThumb(G, B, E, ArmCfg); - - llvm_unreachable("Relocation must be of class Data, Arm or Thumb"); -} - -/// 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>> { -public: - StubsManager() = default; - - /// Name of the object file section that will contain all our stubs. - static StringRef getSectionName() { return "__llvm_jitlink_STUBS"; } - - /// 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; - } - - /// Create a branch range extension stub for the class's flavor. - Symbol &createEntry(LinkGraph &G, Symbol &Target); - -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); - } - - /// 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; - } - - Section *StubsSection = nullptr; -}; - -/// Create a branch range extension stub with Thumb encoding for v7 CPUs. -template <> -Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target); - -} // namespace aarch32 -} // namespace jitlink -} // namespace llvm - -#endif // LLVM_EXECUTIONENGINE_JITLINK_AARCH32 diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt index bc86f45..52ff5e8 100644 --- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt @@ -20,7 +20,6 @@ add_llvm_component_library(LLVMJITLink # ELF ELF.cpp ELFLinkGraphBuilder.cpp - ELF_aarch32.cpp ELF_aarch64.cpp ELF_i386.cpp ELF_loongarch.cpp @@ -34,7 +33,6 @@ add_llvm_component_library(LLVMJITLink COFF_x86_64.cpp # Architectures: - aarch32.cpp aarch64.cpp i386.cpp loongarch.cpp diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp index 340a0ce..ef0f19a 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp @@ -13,7 +13,6 @@ #include "llvm/ExecutionEngine/JITLink/ELF.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h" #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h" #include "llvm/ExecutionEngine/JITLink/ELF_i386.h" #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h" @@ -70,8 +69,6 @@ createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) { switch (*TargetMachineArch) { case ELF::EM_AARCH64: return createLinkGraphFromELFObject_aarch64(ObjectBuffer); - case ELF::EM_ARM: - return createLinkGraphFromELFObject_aarch32(ObjectBuffer); case ELF::EM_LOONGARCH: return createLinkGraphFromELFObject_loongarch(ObjectBuffer); case ELF::EM_RISCV: @@ -93,12 +90,6 @@ void link_ELF(std::unique_ptr<LinkGraph> G, case Triple::aarch64: link_ELF_aarch64(std::move(G), std::move(Ctx)); return; - case Triple::arm: - case Triple::armeb: - case Triple::thumb: - case Triple::thumbeb: - link_ELF_aarch32(std::move(G), std::move(Ctx)); - return; case Triple::loongarch32: case Triple::loongarch64: link_ELF_loongarch(std::move(G), std::move(Ctx)); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h index 1d98acf..9d2d495 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h @@ -127,12 +127,6 @@ protected: Error graphifySections(); Error graphifySymbols(); - /// Override in derived classes to suppress certain sections in the link - /// graph. - virtual bool excludeSection(const typename ELFT::Shdr &Sect) const { - return false; - } - /// Traverse all matching ELFT::Rela relocation records in the given section. /// The handler function Func should be callable with this signature: /// Error(const typename ELFT::Rela &, @@ -327,13 +321,6 @@ template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() { auto Name = Obj.getSectionName(Sec, SectionStringTab); if (!Name) return Name.takeError(); - if (excludeSection(Sec)) { - LLVM_DEBUG({ - dbgs() << " " << SecIndex << ": Skipping section \"" << *Name - << "\" explicitly\n"; - }); - continue; - } // Skip null sections. if (Sec.sh_type == ELF::SHT_NULL) { @@ -577,10 +564,6 @@ Error ELFLinkGraphBuilder<ELFT>::forEachRelaRelocation( LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n"); return Error::success(); } - if (excludeSection(**FixupSection)) { - LLVM_DEBUG(dbgs() << " skipped (fixup section excluded explicitly)\n\n"); - return Error::success(); - } // Lookup the link-graph node corresponding to the target section name. auto *BlockToFix = getGraphBlock(RelSect.sh_info); @@ -627,10 +610,6 @@ Error ELFLinkGraphBuilder<ELFT>::forEachRelRelocation( LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n"); return Error::success(); } - if (excludeSection(**FixupSection)) { - LLVM_DEBUG(dbgs() << " skipped (fixup section excluded explicitly)\n\n"); - return Error::success(); - } // Lookup the link-graph node corresponding to the target section name. auto *BlockToFix = getGraphBlock(RelSect.sh_info); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp deleted file mode 100644 index 0010088..0000000 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp +++ /dev/null @@ -1,299 +0,0 @@ -//===----- ELF_aarch32.cpp - JIT linker implementation for arm/thumb ------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// ELF/aarch32 jit-link implementation. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h" - -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/ExecutionEngine/JITLink/JITLink.h" -#include "llvm/ExecutionEngine/JITLink/aarch32.h" -#include "llvm/Object/ELF.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/TargetParser/ARMTargetParser.h" - -#include "ELFLinkGraphBuilder.h" -#include "JITLinkGeneric.h" - -#define DEBUG_TYPE "jitlink" - -using namespace llvm::object; - -namespace llvm { -namespace jitlink { - -/// Translate from ELF relocation type to JITLink-internal edge kind. -Expected<aarch32::EdgeKind_aarch32> getJITLinkEdgeKind(uint32_t ELFType) { - switch (ELFType) { - case ELF::R_ARM_REL32: - return aarch32::Data_Delta32; - case ELF::R_ARM_CALL: - return aarch32::Arm_Call; - case ELF::R_ARM_THM_CALL: - return aarch32::Thumb_Call; - case ELF::R_ARM_THM_JUMP24: - return aarch32::Thumb_Jump24; - case ELF::R_ARM_THM_MOVW_ABS_NC: - return aarch32::Thumb_MovwAbsNC; - case ELF::R_ARM_THM_MOVT_ABS: - return aarch32::Thumb_MovtAbs; - } - - return make_error<JITLinkError>( - "Unsupported aarch32 relocation " + formatv("{0:d}: ", ELFType) + - object::getELFRelocationTypeName(ELF::EM_ARM, ELFType)); -} - -/// Translate from JITLink-internal edge kind back to ELF relocation type. -Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) { - switch (static_cast<aarch32::EdgeKind_aarch32>(Kind)) { - case aarch32::Data_Delta32: - return ELF::R_ARM_REL32; - case aarch32::Arm_Call: - return ELF::R_ARM_CALL; - case aarch32::Thumb_Call: - return ELF::R_ARM_THM_CALL; - case aarch32::Thumb_Jump24: - return ELF::R_ARM_THM_JUMP24; - case aarch32::Thumb_MovwAbsNC: - return ELF::R_ARM_THM_MOVW_ABS_NC; - case aarch32::Thumb_MovtAbs: - return ELF::R_ARM_THM_MOVT_ABS; - } - - return make_error<JITLinkError>(formatv("Invalid aarch32 edge {0:d}: ", - Kind)); -} - -/// Get a human-readable name for the given ELF AArch32 edge kind. -const char *getELFAArch32EdgeKindName(Edge::Kind R) { - // No ELF-specific edge kinds yet - return aarch32::getEdgeKindName(R); -} - -class ELFJITLinker_aarch32 : public JITLinker<ELFJITLinker_aarch32> { - friend class JITLinker<ELFJITLinker_aarch32>; - -public: - ELFJITLinker_aarch32(std::unique_ptr<JITLinkContext> Ctx, - std::unique_ptr<LinkGraph> G, PassConfiguration PassCfg, - aarch32::ArmConfig ArmCfg) - : JITLinker(std::move(Ctx), std::move(G), std::move(PassCfg)), - ArmCfg(std::move(ArmCfg)) {} - -private: - aarch32::ArmConfig ArmCfg; - - Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { - return aarch32::applyFixup(G, B, E, ArmCfg); - } -}; - -template <support::endianness DataEndianness> -class ELFLinkGraphBuilder_aarch32 - : public ELFLinkGraphBuilder<ELFType<DataEndianness, false>> { -private: - using ELFT = ELFType<DataEndianness, false>; - using Base = ELFLinkGraphBuilder<ELFT>; - - bool excludeSection(const typename ELFT::Shdr &Sect) const override { - // TODO: An .ARM.exidx (Exception Index table) entry is 8-bytes in size and - // consists of 2 words. It might be sufficient to process only relocations - // in the the second word (offset 4). Please find more details in: Exception - // Handling ABI for the ArmĀ® Architecture -> Index table entries - if (Sect.sh_type == ELF::SHT_ARM_EXIDX) - return true; - return false; - } - - Error addRelocations() override { - LLVM_DEBUG(dbgs() << "Processing relocations:\n"); - using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>; - for (const auto &RelSect : Base::Sections) { - if (Error Err = Base::forEachRelRelocation(RelSect, this, - &Self::addSingleRelRelocation)) - return Err; - } - return Error::success(); - } - - Error addSingleRelRelocation(const typename ELFT::Rel &Rel, - const typename ELFT::Shdr &FixupSect, - Block &BlockToFix) { - uint32_t SymbolIndex = Rel.getSymbol(false); - auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); - if (!ObjSymbol) - return ObjSymbol.takeError(); - - Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); - if (!GraphSymbol) - return make_error<StringError>( - formatv("Could not find symbol at given index, did you add it to " - "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", - SymbolIndex, (*ObjSymbol)->st_shndx, - Base::GraphSymbols.size()), - inconvertibleErrorCode()); - - uint32_t Type = Rel.getType(false); - Expected<aarch32::EdgeKind_aarch32> Kind = getJITLinkEdgeKind(Type); - if (!Kind) - return Kind.takeError(); - - auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; - Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); - Edge E(*Kind, Offset, *GraphSymbol, 0); - - Expected<int64_t> Addend = - aarch32::readAddend(*Base::G, BlockToFix, E, ArmCfg); - if (!Addend) - return Addend.takeError(); - - E.setAddend(*Addend); - LLVM_DEBUG({ - dbgs() << " "; - printEdge(dbgs(), BlockToFix, E, getELFAArch32EdgeKindName(*Kind)); - dbgs() << "\n"; - }); - - BlockToFix.addEdge(std::move(E)); - return Error::success(); - } - - aarch32::ArmConfig ArmCfg; - -protected: - TargetFlagsType makeTargetFlags(const typename ELFT::Sym &Sym) override { - if (Sym.getValue() & 0x01) - return aarch32::ThumbSymbol; - return TargetFlagsType{}; - } - - orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym, - TargetFlagsType Flags) override { - assert((makeTargetFlags(Sym) & Flags) == Flags); - static constexpr uint64_t ThumbBit = 0x01; - return Sym.getValue() & ~ThumbBit; - } - -public: - ELFLinkGraphBuilder_aarch32(StringRef FileName, const ELFFile<ELFT> &Obj, - Triple TT, aarch32::ArmConfig ArmCfg) - : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), FileName, - getELFAArch32EdgeKindName), - ArmCfg(std::move(ArmCfg)) {} -}; - -template <aarch32::StubsFlavor Flavor> -Error buildTables_ELF_aarch32(LinkGraph &G) { - LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); - - aarch32::StubsManager<Flavor> PLT; - visitExistingEdges(G, PLT); - return Error::success(); -} - -Expected<std::unique_ptr<LinkGraph>> -createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) { - LLVM_DEBUG({ - dbgs() << "Building jitlink graph for new input " - << ObjectBuffer.getBufferIdentifier() << "...\n"; - }); - - auto ELFObj = ObjectFile::createELFObjectFile(ObjectBuffer); - if (!ELFObj) - return ELFObj.takeError(); - - // Find out what exact AArch32 instruction set and features we target. - auto TT = (*ELFObj)->makeTriple(); - ARM::ArchKind AK = ARM::parseArch(TT.getArchName()); - if (AK == ARM::ArchKind::INVALID) - return make_error<JITLinkError>( - "Failed to build ELF link graph: Invalid ARM ArchKind"); - - // Resolve our internal configuration for the target. If at some point the - // CPUArch alone becomes too unprecise, we can find more details in the - // Tag_CPU_arch_profile. - aarch32::ArmConfig ArmCfg; - using namespace ARMBuildAttrs; - auto Arch = static_cast<CPUArch>(ARM::getArchAttr(AK)); - switch (Arch) { - case v7: - case v8_A: - ArmCfg = aarch32::getArmConfigForCPUArch(Arch); - assert(ArmCfg.Stubs != aarch32::Unsupported && - "Provide a config for each supported CPU"); - break; - default: - return make_error<JITLinkError>( - "Failed to build ELF link graph: Unsupported CPU arch " + - StringRef(aarch32::getCPUArchName(Arch))); - } - - // Populate the link-graph. - switch (TT.getArch()) { - case Triple::arm: - case Triple::thumb: { - auto &ELFFile = cast<ELFObjectFile<ELF32LE>>(**ELFObj).getELFFile(); - return ELFLinkGraphBuilder_aarch32<support::little>( - (*ELFObj)->getFileName(), ELFFile, TT, ArmCfg) - .buildGraph(); - } - case Triple::armeb: - case Triple::thumbeb: { - auto &ELFFile = cast<ELFObjectFile<ELF32BE>>(**ELFObj).getELFFile(); - return ELFLinkGraphBuilder_aarch32<support::big>((*ELFObj)->getFileName(), - ELFFile, TT, ArmCfg) - .buildGraph(); - } - default: - return make_error<JITLinkError>( - "Failed to build ELF/aarch32 link graph: Invalid target triple " + - TT.getTriple()); - } -} - -void link_ELF_aarch32(std::unique_ptr<LinkGraph> G, - std::unique_ptr<JITLinkContext> Ctx) { - const Triple &TT = G->getTargetTriple(); - - using namespace ARMBuildAttrs; - ARM::ArchKind AK = ARM::parseArch(TT.getArchName()); - auto CPU = static_cast<CPUArch>(ARM::getArchAttr(AK)); - aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPU); - - PassConfiguration PassCfg; - if (Ctx->shouldAddDefaultTargetPasses(TT)) { - // Add a mark-live pass. - if (auto MarkLive = Ctx->getMarkLivePass(TT)) - PassCfg.PrePrunePasses.push_back(std::move(MarkLive)); - else - PassCfg.PrePrunePasses.push_back(markAllSymbolsLive); - - switch (ArmCfg.Stubs) { - case aarch32::Thumbv7: - PassCfg.PostPrunePasses.push_back( - buildTables_ELF_aarch32<aarch32::Thumbv7>); - break; - case aarch32::Unsupported: - llvm_unreachable("Check before building graph"); - } - } - - if (auto Err = Ctx->modifyPassConfig(*G, PassCfg)) - return Ctx->notifyFailed(std::move(Err)); - - ELFJITLinker_aarch32::link(std::move(Ctx), std::move(G), std::move(PassCfg), - std::move(ArmCfg)); -} - -} // namespace jitlink -} // namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp deleted file mode 100644 index 6f49a45..0000000 --- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp +++ /dev/null @@ -1,514 +0,0 @@ -//===--------- aarch32.cpp - Generic JITLink arm/thumb utilities ----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Generic utilities for graphs representing arm/thumb objects. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/JITLink/aarch32.h" - -#include "llvm/ADT/StringExtras.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/ExecutionEngine/JITLink/JITLink.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/MathExtras.h" - -#define DEBUG_TYPE "jitlink" - -namespace llvm { -namespace jitlink { -namespace aarch32 { - -using namespace support; -using namespace support::endian; - -/// Encode 22-bit immediate value for branch instructions without J1J2 range -/// extension (formats B T4, BL T1 and BLX T2). -/// -/// 00000:Imm11H:Imm11L:0 -> [ 00000:Imm11H, 00000:Imm11L ] -/// J1^ ^J2 will always be 1 -/// -HalfWords encodeImmBT4BlT1BlxT2(int64_t Value) { - constexpr uint32_t J1J2 = 0x2800; - uint32_t Imm11H = (Value >> 12) & 0x07ff; - uint32_t Imm11L = (Value >> 1) & 0x07ff; - return HalfWords{Imm11H, Imm11L | J1J2}; -} - -/// Decode 22-bit immediate value for branch instructions without J1J2 range -/// extension (formats B T4, BL T1 and BLX T2). -/// -/// [ 00000:Imm11H, 00000:Imm11L ] -> 00000:Imm11H:Imm11L:0 -/// J1^ ^J2 will always be 1 -/// -int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo) { - uint32_t Imm11H = Hi & 0x07ff; - uint32_t Imm11L = Lo & 0x07ff; - return SignExtend64<22>(Imm11H << 12 | Imm11L << 1); -} - -/// Encode 25-bit immediate value for branch instructions with J1J2 range -/// extension (formats B T4, BL T1 and BLX T2). -/// -/// S:I1:I2:Imm10:Imm11:0 -> [ 00000:S:Imm10, 00:J1:0:J2:Imm11 ] -/// -HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value) { - uint32_t S = (Value >> 14) & 0x0400; - uint32_t J1 = (((~(Value >> 10)) ^ (Value >> 11)) & 0x2000); - uint32_t J2 = (((~(Value >> 11)) ^ (Value >> 13)) & 0x0800); - uint32_t Imm10 = (Value >> 12) & 0x03ff; - uint32_t Imm11 = (Value >> 1) & 0x07ff; - return HalfWords{S | Imm10, J1 | J2 | Imm11}; -} - -/// Decode 25-bit immediate value for branch instructions with J1J2 range -/// extension (formats B T4, BL T1 and BLX T2). -/// -/// [ 00000:S:Imm10, 00:J1:0:J2:Imm11] -> S:I1:I2:Imm10:Imm11:0 -/// -int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo) { - uint32_t S = Hi & 0x0400; - uint32_t I1 = ~((Lo ^ (Hi << 3)) << 10) & 0x00800000; - uint32_t I2 = ~((Lo ^ (Hi << 1)) << 11) & 0x00400000; - uint32_t Imm10 = Hi & 0x03ff; - uint32_t Imm11 = Lo & 0x07ff; - return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1); -} - -/// Encode 16-bit immediate value for move instruction formats MOVT T1 and -/// MOVW T3. -/// -/// Imm4:Imm1:Imm3:Imm8 -> [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -/// -HalfWords encodeImmMovtT1MovwT3(uint16_t Value) { - uint32_t Imm4 = (Value >> 12) & 0x0f; - uint32_t Imm1 = (Value >> 11) & 0x01; - uint32_t Imm3 = (Value >> 8) & 0x07; - uint32_t Imm8 = Value & 0xff; - return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8}; -} - -/// Decode 16-bit immediate value from move instruction formats MOVT T1 and -/// MOVW T3. -/// -/// [ 00000:i:000000:Imm4, 0:Imm3:0000:Imm8 ] -> Imm4:Imm1:Imm3:Imm8 -/// -uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { - uint32_t Imm4 = Hi & 0x0f; - uint32_t Imm1 = (Hi >> 10) & 0x01; - uint32_t Imm3 = (Lo >> 12) & 0x07; - uint32_t Imm8 = Lo & 0xff; - uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8; - assert(Imm16 <= 0xffff && "Decoded value out-of-range"); - return Imm16; -} - -/// Encode register ID for instruction formats MOVT T1 and MOVW T3. -/// -/// Rd4 -> [0000000000000000, 0000:Rd4:00000000] -/// -HalfWords encodeRegMovtT1MovwT3(int64_t Value) { - uint32_t Rd4 = (Value & 0x0f) << 8; - return HalfWords{0, Rd4}; -} - -/// Decode register ID from instruction formats MOVT T1 and MOVW T3. -/// -/// [0000000000000000, 0000:Rd4:00000000] -> Rd4 -/// -int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo) { - uint32_t Rd4 = (Lo >> 8) & 0x0f; - return Rd4; -} - -/// 32-bit Thumb instructions are stored as two little-endian halfwords. -/// An instruction at address A encodes bytes A+1, A in the first halfword (Hi), -/// followed by bytes A+3, A+2 in the second halfword (Lo). -struct WritableThumbRelocation { - /// Create a writable reference to a Thumb32 fixup. - WritableThumbRelocation(char *FixupPtr) - : Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)}, - Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {} - - support::ulittle16_t &Hi; // First halfword - support::ulittle16_t &Lo; // Second halfword -}; - -struct ThumbRelocation { - /// Create a read-only reference to a Thumb32 fixup. - ThumbRelocation(const char *FixupPtr) - : Hi{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr)}, - Lo{*reinterpret_cast<const support::ulittle16_t *>(FixupPtr + 2)} {} - - /// Create a read-only Thumb32 fixup from a writeable one. - ThumbRelocation(WritableThumbRelocation &Writable) - : Hi{Writable.Hi}, Lo(Writable.Lo) {} - - const support::ulittle16_t &Hi; // First halfword - const support::ulittle16_t &Lo; // Second halfword -}; - -Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, - Edge::Kind Kind) { - return make_error<JITLinkError>( - formatv("Invalid opcode [ 0x{0:x4}, 0x{1:x4} ] for relocation: {2}", R.Hi, - R.Lo, G.getEdgeKindName(Kind))); -} - -template <EdgeKind_aarch32 Kind> bool checkOpcode(const ThumbRelocation &R) { - uint16_t Hi = R.Hi & FixupInfo<Kind>::OpcodeMask.Hi; - uint16_t Lo = R.Lo & FixupInfo<Kind>::OpcodeMask.Lo; - return Hi == FixupInfo<Kind>::Opcode.Hi && Lo == FixupInfo<Kind>::Opcode.Lo; -} - -template <EdgeKind_aarch32 Kind> -bool checkRegister(const ThumbRelocation &R, HalfWords Reg) { - uint16_t Hi = R.Hi & FixupInfo<Kind>::RegMask.Hi; - uint16_t Lo = R.Lo & FixupInfo<Kind>::RegMask.Lo; - return Hi == Reg.Hi && Lo == Reg.Lo; -} - -template <EdgeKind_aarch32 Kind> -bool writeRegister(WritableThumbRelocation &R, HalfWords Reg) { - static constexpr HalfWords Mask = FixupInfo<Kind>::RegMask; - assert((Mask.Hi & Reg.Hi) == Reg.Hi && (Mask.Hi & Reg.Hi) == Reg.Hi && - "Value bits exceed bit range of given mask"); - R.Hi = (R.Hi & ~Mask.Hi) | Reg.Hi; - R.Lo = (R.Lo & ~Mask.Lo) | Reg.Lo; -} - -template <EdgeKind_aarch32 Kind> -void writeImmediate(WritableThumbRelocation &R, HalfWords Imm) { - static constexpr HalfWords Mask = FixupInfo<Kind>::ImmMask; - assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Hi & Imm.Hi) == Imm.Hi && - "Value bits exceed bit range of given mask"); - R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi; - R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo; -} - -Expected<int64_t> readAddendData(LinkGraph &G, Block &B, const Edge &E) { - endianness Endian = G.getEndianness(); - assert(Endian != native && "Declare as little or big explicitly"); - - Edge::Kind Kind = E.getKind(); - const char *BlockWorkingMem = B.getContent().data(); - const char *FixupPtr = BlockWorkingMem + E.getOffset(); - - switch (Kind) { - case Data_Delta32: - return SignExtend64<32>((Endian == little) ? read32<little>(FixupPtr) - : read32<big>(FixupPtr)); - default: - return make_error<JITLinkError>( - "In graph " + G.getName() + ", section " + B.getSection().getName() + - " can not read implicit addend for aarch32 edge kind " + - G.getEdgeKindName(E.getKind())); - } -} - -Expected<int64_t> readAddendArm(LinkGraph &G, Block &B, const Edge &E) { - Edge::Kind Kind = E.getKind(); - - switch (Kind) { - case Arm_Call: - return make_error<JITLinkError>( - "Addend extraction for relocation type not yet implemented: " + - StringRef(G.getEdgeKindName(Kind))); - default: - return make_error<JITLinkError>( - "In graph " + G.getName() + ", section " + B.getSection().getName() + - " can not read implicit addend for aarch32 edge kind " + - G.getEdgeKindName(E.getKind())); - } -} - -Expected<int64_t> readAddendThumb(LinkGraph &G, Block &B, const Edge &E, - const ArmConfig &ArmCfg) { - ThumbRelocation R(B.getContent().data() + E.getOffset()); - Edge::Kind Kind = E.getKind(); - - switch (Kind) { - case Thumb_Call: - if (!checkOpcode<Thumb_Call>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) - ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) - : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); - - case Thumb_Jump24: - if (!checkOpcode<Thumb_Jump24>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional) - return make_error<JITLinkError>("Relocation expects an unconditional " - "B.W branch instruction: " + - StringRef(G.getEdgeKindName(Kind))); - return LLVM_LIKELY(ArmCfg.J1J2BranchEncoding) - ? decodeImmBT4BlT1BlxT2_J1J2(R.Hi, R.Lo) - : decodeImmBT4BlT1BlxT2(R.Hi, R.Lo); - - case Thumb_MovwAbsNC: - if (!checkOpcode<Thumb_MovwAbsNC>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - // Initial addend is interpreted as a signed value - return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); - - case Thumb_MovtAbs: - if (!checkOpcode<Thumb_MovtAbs>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - // Initial addend is interpreted as a signed value - return SignExtend64<16>(decodeImmMovtT1MovwT3(R.Hi, R.Lo)); - - default: - return make_error<JITLinkError>( - "In graph " + G.getName() + ", section " + B.getSection().getName() + - " can not read implicit addend for aarch32 edge kind " + - G.getEdgeKindName(E.getKind())); - } -} - -Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) { - using namespace support; - - char *BlockWorkingMem = B.getAlreadyMutableContent().data(); - char *FixupPtr = BlockWorkingMem + E.getOffset(); - - auto Write32 = [FixupPtr, Endian = G.getEndianness()](int64_t Value) { - assert(Endian != native && "Must be explicit: little or big"); - assert(isInt<32>(Value) && "Must be in signed 32-bit range"); - uint32_t Imm = static_cast<int32_t>(Value); - if (LLVM_LIKELY(Endian == little)) - endian::write32<little>(FixupPtr, Imm); - else - endian::write32<big>(FixupPtr, Imm); - }; - - Edge::Kind Kind = E.getKind(); - uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); - int64_t Addend = E.getAddend(); - Symbol &TargetSymbol = E.getTarget(); - uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); - assert(!TargetSymbol.hasTargetFlags(ThumbSymbol)); - - // Regular data relocations have size 4, alignment 1 and write the full 32-bit - // result to the place; no need for overflow checking. There are three - // exceptions: R_ARM_ABS8, R_ARM_ABS16, R_ARM_PREL31 - switch (Kind) { - case Data_Delta32: { - int64_t Value = TargetAddress - FixupAddress + Addend; - if (!isInt<32>(Value)) - return makeTargetOutOfRangeError(G, B, E); - Write32(Value); - return Error::success(); - } - default: - return make_error<JITLinkError>( - "In graph " + G.getName() + ", section " + B.getSection().getName() + - " encountered unfixable aarch32 edge kind " + - G.getEdgeKindName(E.getKind())); - } -} - -Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E) { - Edge::Kind Kind = E.getKind(); - - switch (Kind) { - case Arm_Call: - return make_error<JITLinkError>( - "Fix-up for relocation type not yet implemented: " + - StringRef(G.getEdgeKindName(Kind))); - default: - return make_error<JITLinkError>( - "In graph " + G.getName() + ", section " + B.getSection().getName() + - " encountered unfixable aarch32 edge kind " + - G.getEdgeKindName(E.getKind())); - } -} - -Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, - const ArmConfig &ArmCfg) { - WritableThumbRelocation R(B.getAlreadyMutableContent().data() + - E.getOffset()); - - Edge::Kind Kind = E.getKind(); - uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue(); - int64_t Addend = E.getAddend(); - Symbol &TargetSymbol = E.getTarget(); - uint64_t TargetAddress = TargetSymbol.getAddress().getValue(); - if (TargetSymbol.hasTargetFlags(ThumbSymbol)) - TargetAddress |= 0x01; - - switch (Kind) { - case Thumb_Jump24: { - if (!checkOpcode<Thumb_Jump24>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - if (R.Lo & FixupInfo<Thumb_Jump24>::LoBitConditional) - return make_error<JITLinkError>("Relocation expects an unconditional " - "B.W branch instruction: " + - StringRef(G.getEdgeKindName(Kind))); - if (!(TargetSymbol.hasTargetFlags(ThumbSymbol))) - return make_error<JITLinkError>("Branch relocation needs interworking " - "stub when bridging to ARM: " + - StringRef(G.getEdgeKindName(Kind))); - - int64_t Value = TargetAddress - FixupAddress + Addend; - if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { - if (!isInt<25>(Value)) - return makeTargetOutOfRangeError(G, B, E); - writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); - } else { - if (!isInt<22>(Value)) - return makeTargetOutOfRangeError(G, B, E); - writeImmediate<Thumb_Jump24>(R, encodeImmBT4BlT1BlxT2(Value)); - } - - return Error::success(); - } - - case Thumb_Call: { - if (!checkOpcode<Thumb_Call>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - - int64_t Value = TargetAddress - FixupAddress + Addend; - - // The call instruction itself is Thumb. The call destination can either be - // Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm. - bool TargetIsArm = !TargetSymbol.hasTargetFlags(ThumbSymbol); - bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0; - if (TargetIsArm != InstrIsBlx) { - if (LLVM_LIKELY(TargetIsArm)) { - // Change opcode BL -> BLX and fix range value (account for 4-byte - // aligned destination while instruction may only be 2-byte aligned - // and clear Thumb bit). - R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; - R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitH; - Value = alignTo(Value, 4); - } else { - // Change opcode BLX -> BL and set Thumb bit - R.Lo = R.Lo & ~FixupInfo<Thumb_Call>::LoBitNoBlx; - Value |= 0x01; - } - } - - if (LLVM_LIKELY(ArmCfg.J1J2BranchEncoding)) { - if (!isInt<25>(Value)) - return makeTargetOutOfRangeError(G, B, E); - writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2_J1J2(Value)); - } else { - if (!isInt<22>(Value)) - return makeTargetOutOfRangeError(G, B, E); - writeImmediate<Thumb_Call>(R, encodeImmBT4BlT1BlxT2(Value)); - } - - assert(((R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) || - (R.Lo & FixupInfo<Thumb_Call>::LoBitH) == 0) && - "Opcode BLX implies H bit is clear (avoid UB in BLX T2)"); - return Error::success(); - } - - case Thumb_MovwAbsNC: { - if (!checkOpcode<Thumb_MovwAbsNC>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - uint16_t Value = (TargetAddress + Addend) & 0xffff; - writeImmediate<Thumb_MovwAbsNC>(R, encodeImmMovtT1MovwT3(Value)); - return Error::success(); - } - - case Thumb_MovtAbs: { - if (!checkOpcode<Thumb_MovtAbs>(R)) - return makeUnexpectedOpcodeError(G, R, Kind); - uint16_t Value = ((TargetAddress + Addend) >> 16) & 0xffff; - writeImmediate<Thumb_MovtAbs>(R, encodeImmMovtT1MovwT3(Value)); - return Error::success(); - } - - default: - return make_error<JITLinkError>( - "In graph " + G.getName() + ", section " + B.getSection().getName() + - " encountered unfixable aarch32 edge kind " + - G.getEdgeKindName(E.getKind())); - } -} - -const uint8_t Thumbv7ABS[] = { - 0x40, 0xf2, 0x00, 0x0c, // movw r12, #0x0000 ; lower 16-bit - 0xc0, 0xf2, 0x00, 0x0c, // movt r12, #0x0000 ; upper 16-bit - 0x60, 0x47 // bx r12 -}; - -template <> -Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target) { - constexpr uint64_t Alignment = 4; - Block &B = addStub(G, Thumbv7ABS, Alignment); - LLVM_DEBUG({ - const char *StubPtr = B.getContent().data(); - HalfWords Reg12 = encodeRegMovtT1MovwT3(12); - assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) && - checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) && - "Linker generated stubs may only corrupt register r12 (IP)"); - }); - B.addEdge(Thumb_MovwAbsNC, 0, Target, 0); - B.addEdge(Thumb_MovtAbs, 4, Target, 0); - Symbol &Stub = G.addAnonymousSymbol(B, 0, B.getSize(), true, false); - Stub.setTargetFlags(ThumbSymbol); - return Stub; -} - -const char *getEdgeKindName(Edge::Kind K) { -#define KIND_NAME_CASE(K) \ - case K: \ - return #K; - - switch (K) { - KIND_NAME_CASE(Data_Delta32) - KIND_NAME_CASE(Arm_Call) - KIND_NAME_CASE(Thumb_Call) - KIND_NAME_CASE(Thumb_Jump24) - KIND_NAME_CASE(Thumb_MovwAbsNC) - KIND_NAME_CASE(Thumb_MovtAbs) - default: - return getGenericEdgeKindName(K); - } -#undef KIND_NAME_CASE -} - -const char *getCPUArchName(ARMBuildAttrs::CPUArch K) { -#define CPUARCH_NAME_CASE(K) \ - case K: \ - return #K; - - using namespace ARMBuildAttrs; - switch (K) { - CPUARCH_NAME_CASE(Pre_v4) - CPUARCH_NAME_CASE(v4) - CPUARCH_NAME_CASE(v4T) - CPUARCH_NAME_CASE(v5T) - CPUARCH_NAME_CASE(v5TE) - CPUARCH_NAME_CASE(v5TEJ) - CPUARCH_NAME_CASE(v6) - CPUARCH_NAME_CASE(v6KZ) - CPUARCH_NAME_CASE(v6T2) - CPUARCH_NAME_CASE(v6K) - CPUARCH_NAME_CASE(v7) - CPUARCH_NAME_CASE(v6_M) - CPUARCH_NAME_CASE(v6S_M) - CPUARCH_NAME_CASE(v7E_M) - CPUARCH_NAME_CASE(v8_A) - CPUARCH_NAME_CASE(v8_R) - CPUARCH_NAME_CASE(v8_M_Base) - CPUARCH_NAME_CASE(v8_M_Main) - CPUARCH_NAME_CASE(v8_1_M_Main) - CPUARCH_NAME_CASE(v9_A) - } - llvm_unreachable("Missing CPUArch in switch?"); -#undef CPUARCH_NAME_CASE -} - -} // namespace aarch32 -} // namespace jitlink -} // namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 83a09b8..2c270cd 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -8,7 +8,6 @@ #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" -#include "llvm/ExecutionEngine/JITLink/aarch32.h" #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" @@ -41,10 +40,7 @@ bool hasInitializerSection(jitlink::LinkGraph &G) { } JITTargetAddress getJITSymbolPtrForSymbol(Symbol &Sym) { - uint64_t CallableAddr = Sym.getAddress().getValue(); - if (Sym.isCallable() && Sym.hasTargetFlags(aarch32::ThumbSymbol)) - CallableAddr |= 0x01; // thumb bit - return CallableAddr; + return Sym.getAddress().getValue(); } JITSymbolFlags getJITSymbolFlagsForSymbol(Symbol &Sym) { diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumbv7_printf.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumbv7_printf.s deleted file mode 100644 index 11a77c9..0000000 --- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumbv7_printf.s +++ /dev/null @@ -1,46 +0,0 @@ -// RUN: llvm-mc -triple=thumbv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t.o %s -// RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 -abs printf=0x76bbe880 -show-entry-es %t.o | FileCheck %s - -// Check that main is a thumb symbol (with LSB set) and printf is arm (with LSB clear) -// -// CHECK-LABEL: Symbol table: -// CHECK-NEXT: "main": 0x{{[0-9a-f]+[13579bdf]}} [Callable] Ready -// CHECK-NEXT: "printf": 0x76bbe880 [Data] Ready - - .globl main - .p2align 2 - .type main,%function - .code 16 - .thumb_func -main: - .fnstart - .save {r7, lr} - push {r7, lr} - .setfp r7, sp - mov r7, sp - .pad #8 - sub sp, #8 - movs r0, #0 - str r0, [sp] - str r0, [sp, #4] - ldr r0, .LCPI0_0 -.LPC0_0: - add r0, pc - bl printf - ldr r0, [sp] - add sp, #8 - pop {r7, pc} - - .p2align 2 -.LCPI0_0: - .long .L.str-(.LPC0_0+4) - - .size main, .-main - .cantunwind - .fnend - - .type .L.str,%object - .section .rodata.str1.1,"aMS",%progbits,1 -.L.str: - .asciz "Hello AArch32!\n" - .size .L.str, 12 diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/lit.local.cfg b/llvm/test/ExecutionEngine/JITLink/AArch32/lit.local.cfg deleted file mode 100644 index 20e19ae..0000000 --- a/llvm/test/ExecutionEngine/JITLink/AArch32/lit.local.cfg +++ /dev/null @@ -1,2 +0,0 @@ -if not 'ARM' in config.root.targets: - config.unsupported = True diff --git a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp b/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp deleted file mode 100644 index 0e41174..0000000 --- a/llvm/unittests/ExecutionEngine/JITLink/AArch32Tests.cpp +++ /dev/null @@ -1,200 +0,0 @@ -//===------- AArch32Tests.cpp - Unit tests for the AArch32 backend --------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include <llvm/BinaryFormat/ELF.h> -#include <llvm/ExecutionEngine/JITLink/aarch32.h> - -#include "gtest/gtest.h" - -using namespace llvm; -using namespace llvm::jitlink; -using namespace llvm::jitlink::aarch32; -using namespace llvm::support; -using namespace llvm::support::endian; - -struct MutableHalfWords { - MutableHalfWords(HalfWords Preset) : Hi(Preset.Hi), Lo(Preset.Lo) {} - - void patch(HalfWords Value, HalfWords Mask) { - Hi = (Hi & ~Mask.Hi) | Value.Hi; - Lo = (Lo & ~Mask.Lo) | Value.Lo; - } - - uint16_t Hi; // First halfword - uint16_t Lo; // Second halfword -}; - -namespace llvm { -namespace jitlink { - -Expected<aarch32::EdgeKind_aarch32> getJITLinkEdgeKind(uint32_t ELFType); -Expected<uint32_t> getELFRelocationType(Edge::Kind Kind); - -} // namespace jitlink -} // namespace llvm - -TEST(AArch32_ELF, EdgeKinds) { - // Fails: Invalid ELF type -> JITLink kind - Expected<uint32_t> ErrKind = getJITLinkEdgeKind(ELF::R_ARM_NONE); - EXPECT_TRUE(errorToBool(ErrKind.takeError())); - - // Fails: Invalid JITLink kind -> ELF type - Expected<uint32_t> ErrType = getELFRelocationType(Edge::Invalid); - EXPECT_TRUE(errorToBool(ErrType.takeError())); - - for (Edge::Kind K = FirstDataRelocation; K < LastThumbRelocation; K += 1) { - Expected<uint32_t> ELFType = getELFRelocationType(K); - EXPECT_FALSE(errorToBool(ELFType.takeError())) - << "Failed to translate JITLink kind -> ELF type"; - - Expected<Edge::Kind> JITLinkKind = getJITLinkEdgeKind(*ELFType); - EXPECT_FALSE(errorToBool(JITLinkKind.takeError())) - << "Failed to translate ELF type -> JITLink kind"; - - EXPECT_EQ(*JITLinkKind, K) << "Round-trip value inconsistent?"; - } -} - -namespace llvm { -namespace jitlink { -namespace aarch32 { - -HalfWords encodeImmBT4BlT1BlxT2(int64_t Value); -HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value); -HalfWords encodeImmMovtT1MovwT3(uint16_t Value); -HalfWords encodeRegMovtT1MovwT3(int64_t Value); - -int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo); -int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo); -uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo); -int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo); - -} // namespace aarch32 -} // namespace jitlink -} // namespace llvm - -// Big-endian for v7 and v8 (and v6 unless in legacy backwards compatible mode -// be32) have little-endian instructions and big-endian data. In ELF relocatable -// objects big-endian instructions may still be encountered. A be8 supporting -// linker is expected to endian-reverse instructions for the executable. -template <endianness Endian> -static HalfWords makeHalfWords(std::array<uint8_t, 4> Mem) { - return HalfWords{read16<Endian>(Mem.data()), read16<Endian>(Mem.data() + 2)}; -} - -/// 25-bit branch with link (with J1J2 range extension) -TEST(AArch32_Relocations, Thumb_Call_J1J2) { - static_assert(isInt<25>(16777215), "Max value"); - static_assert(isInt<25>(-16777215), "Min value"); - static_assert(!isInt<25>(16777217), "First overflow"); - static_assert(!isInt<25>(-16777217), "First underflow"); - - constexpr HalfWords ImmMask = FixupInfo<Thumb_Call>::ImmMask; - - static std::array<HalfWords, 3> MemPresets{ - makeHalfWords<little>({0xff, 0xf7, 0xfe, 0xef}), // common - makeHalfWords<little>({0x00, 0x00, 0x00, 0x00}), // zeros - makeHalfWords<little>({0xff, 0xff, 0xff, 0xff}), // ones - }; - - auto EncodeDecode = [ImmMask](int64_t In, MutableHalfWords &Mem) { - Mem.patch(encodeImmBT4BlT1BlxT2_J1J2(In), ImmMask); - return decodeImmBT4BlT1BlxT2_J1J2(Mem.Hi, Mem.Lo); - }; - - for (MutableHalfWords Mem : MemPresets) { - HalfWords UnaffectedBits(Mem.Hi & ~ImmMask.Hi, Mem.Lo & ~ImmMask.Lo); - - EXPECT_EQ(EncodeDecode(1, Mem), 0); // Zero value - EXPECT_EQ(EncodeDecode(0x41, Mem), 0x40); // Common value - EXPECT_EQ(EncodeDecode(16777215, Mem), 16777214); // Maximum value - EXPECT_EQ(EncodeDecode(-16777215, Mem), -16777216); // Minimum value - EXPECT_NE(EncodeDecode(16777217, Mem), 16777217); // First overflow - EXPECT_NE(EncodeDecode(-16777217, Mem), -16777217); // First underflow - - EXPECT_TRUE(UnaffectedBits.Hi == (Mem.Hi & ~ImmMask.Hi) && - UnaffectedBits.Lo == (Mem.Lo & ~ImmMask.Lo)) - << "Diff outside immediate field"; - } -} - -/// 22-bit branch with link (without J1J2 range extension) -TEST(AArch32_Relocations, Thumb_Call_Bare) { - static_assert(isInt<22>(2097151), "Max value"); - static_assert(isInt<22>(-2097151), "Min value"); - static_assert(!isInt<22>(2097153), "First overflow"); - static_assert(!isInt<22>(-2097153), "First underflow"); - - constexpr HalfWords ImmMask = FixupInfo<Thumb_Call>::ImmMask; - - static std::array<HalfWords, 3> MemPresets{ - makeHalfWords<little>({0xff, 0xf7, 0xfe, 0xef}), // common - makeHalfWords<little>({0x00, 0x00, 0x00, 0x00}), // zeros - makeHalfWords<little>({0xff, 0xff, 0xff, 0xff}), // ones - }; - - auto EncodeDecode = [ImmMask](int64_t In, MutableHalfWords &Mem) { - Mem.patch(encodeImmBT4BlT1BlxT2_J1J2(In), ImmMask); - return decodeImmBT4BlT1BlxT2_J1J2(Mem.Hi, Mem.Lo); - }; - - for (MutableHalfWords Mem : MemPresets) { - HalfWords UnaffectedBits(Mem.Hi & ~ImmMask.Hi, Mem.Lo & ~ImmMask.Lo); - - EXPECT_EQ(EncodeDecode(1, Mem), 0); // Zero value - EXPECT_EQ(EncodeDecode(0x41, Mem), 0x40); // Common value - EXPECT_EQ(EncodeDecode(2097151, Mem), 2097150); // Maximum value - EXPECT_EQ(EncodeDecode(-2097151, Mem), -2097152); // Minimum value - EXPECT_NE(EncodeDecode(2097153, Mem), 2097153); // First overflow - EXPECT_NE(EncodeDecode(-2097153, Mem), -2097153); // First underflow - - EXPECT_TRUE(UnaffectedBits.Hi == (Mem.Hi & ~ImmMask.Hi) && - UnaffectedBits.Lo == (Mem.Lo & ~ImmMask.Lo)) - << "Diff outside immediate field"; - } -} - -/// Write immediate value to the top halfword of the destination register -TEST(AArch32_Relocations, Thumb_MovtAbs) { - static_assert(isUInt<16>(65535), "Max value"); - static_assert(!isUInt<16>(65536), "First overflow"); - - constexpr HalfWords ImmMask = FixupInfo<Thumb_MovtAbs>::ImmMask; - constexpr HalfWords RegMask = FixupInfo<Thumb_MovtAbs>::RegMask; - - static std::array<uint8_t, 3> Registers{0, 5, 12}; - static std::array<HalfWords, 3> MemPresets{ - makeHalfWords<little>({0xff, 0xf7, 0xfe, 0xef}), // common - makeHalfWords<little>({0x00, 0x00, 0x00, 0x00}), // zeros - makeHalfWords<little>({0xff, 0xff, 0xff, 0xff}), // ones - }; - - auto EncodeDecode = [ImmMask](uint32_t In, MutableHalfWords &Mem) { - Mem.patch(encodeImmMovtT1MovwT3(In), ImmMask); - return decodeImmMovtT1MovwT3(Mem.Hi, Mem.Lo); - }; - - for (MutableHalfWords Mem : MemPresets) { - for (uint8_t Reg : Registers) { - HalfWords UnaffectedBits(Mem.Hi & ~(ImmMask.Hi | RegMask.Hi), - Mem.Lo & ~(ImmMask.Lo | RegMask.Lo)); - - Mem.patch(encodeRegMovtT1MovwT3(Reg), RegMask); - EXPECT_EQ(EncodeDecode(0x76bb, Mem), 0x76bb); // Common value - EXPECT_EQ(EncodeDecode(0, Mem), 0); // Minimum value - EXPECT_EQ(EncodeDecode(0xffff, Mem), 0xffff); // Maximum value - EXPECT_NE(EncodeDecode(0x10000, Mem), 0x10000); // First overflow - - // Destination register as well as unaffacted bits should be intact - EXPECT_EQ(decodeRegMovtT1MovwT3(Mem.Hi, Mem.Lo), Reg); - EXPECT_TRUE(UnaffectedBits.Hi == (Mem.Hi & ~(ImmMask.Hi | RegMask.Hi)) && - UnaffectedBits.Lo == (Mem.Lo & ~(ImmMask.Lo | RegMask.Lo))) - << "Diff outside immediate/register field"; - } - } -} diff --git a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt index 978914c..1a71a62 100644 --- a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt +++ b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt @@ -8,7 +8,6 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(JITLinkTests - AArch32Tests.cpp EHFrameSupportTests.cpp LinkGraphTests.cpp ) |