1f10d452dSwanglei //===--- ELF_loongarch.cpp - JIT linker implementation for ELF/loongarch --===// 2f10d452dSwanglei // 3f10d452dSwanglei // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f10d452dSwanglei // See https://llvm.org/LICENSE.txt for license information. 5f10d452dSwanglei // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f10d452dSwanglei // 7f10d452dSwanglei //===----------------------------------------------------------------------===// 8f10d452dSwanglei // 9f10d452dSwanglei // ELF/loongarch jit-link implementation. 10f10d452dSwanglei // 11f10d452dSwanglei //===----------------------------------------------------------------------===// 12f10d452dSwanglei 13f10d452dSwanglei #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h" 14f10d452dSwanglei #include "llvm/BinaryFormat/ELF.h" 15f10d452dSwanglei #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" 16f10d452dSwanglei #include "llvm/ExecutionEngine/JITLink/JITLink.h" 17f10d452dSwanglei #include "llvm/ExecutionEngine/JITLink/loongarch.h" 18f10d452dSwanglei #include "llvm/Object/ELF.h" 19f10d452dSwanglei #include "llvm/Object/ELFObjectFile.h" 20f10d452dSwanglei 21f10d452dSwanglei #include "EHFrameSupportImpl.h" 22f10d452dSwanglei #include "ELFLinkGraphBuilder.h" 23f10d452dSwanglei #include "JITLinkGeneric.h" 24f10d452dSwanglei 25f10d452dSwanglei #define DEBUG_TYPE "jitlink" 26f10d452dSwanglei 27f10d452dSwanglei using namespace llvm; 28f10d452dSwanglei using namespace llvm::jitlink; 29f10d452dSwanglei using namespace llvm::jitlink::loongarch; 30f10d452dSwanglei 31f10d452dSwanglei namespace { 32f10d452dSwanglei 33f10d452dSwanglei class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> { 34f10d452dSwanglei friend class JITLinker<ELFJITLinker_loongarch>; 35f10d452dSwanglei 36f10d452dSwanglei public: 37f10d452dSwanglei ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx, 38f10d452dSwanglei std::unique_ptr<LinkGraph> G, 39f10d452dSwanglei PassConfiguration PassConfig) 40f10d452dSwanglei : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 41f10d452dSwanglei 42f10d452dSwanglei private: 43f10d452dSwanglei Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 44f10d452dSwanglei return loongarch::applyFixup(G, B, E); 45f10d452dSwanglei } 46f10d452dSwanglei }; 47f10d452dSwanglei 489dd5aed4SZhaoQi namespace { 499dd5aed4SZhaoQi 509dd5aed4SZhaoQi struct SymbolAnchor { 519dd5aed4SZhaoQi uint64_t Offset; 529dd5aed4SZhaoQi Symbol *Sym; 539dd5aed4SZhaoQi bool End; // true for the anchor of getOffset() + getSize() 549dd5aed4SZhaoQi }; 559dd5aed4SZhaoQi 569dd5aed4SZhaoQi struct BlockRelaxAux { 579dd5aed4SZhaoQi // This records symbol start and end offsets which will be adjusted according 589dd5aed4SZhaoQi // to the nearest RelocDeltas element. 599dd5aed4SZhaoQi SmallVector<SymbolAnchor, 0> Anchors; 609dd5aed4SZhaoQi // All edges that either 1) are R_LARCH_ALIGN or 2) have a R_LARCH_RELAX edge 619dd5aed4SZhaoQi // at the same offset. 629dd5aed4SZhaoQi SmallVector<Edge *, 0> RelaxEdges; 639dd5aed4SZhaoQi // For RelaxEdges[I], the actual offset is RelaxEdges[I]->getOffset() - (I ? 649dd5aed4SZhaoQi // RelocDeltas[I - 1] : 0). 659dd5aed4SZhaoQi SmallVector<uint32_t, 0> RelocDeltas; 669dd5aed4SZhaoQi // For RelaxEdges[I], the actual type is EdgeKinds[I]. 679dd5aed4SZhaoQi SmallVector<Edge::Kind, 0> EdgeKinds; 689dd5aed4SZhaoQi // List of rewritten instructions. Contains one raw encoded instruction per 699dd5aed4SZhaoQi // element in EdgeKinds that isn't Invalid or R_LARCH_ALIGN. 709dd5aed4SZhaoQi SmallVector<uint32_t, 0> Writes; 719dd5aed4SZhaoQi }; 729dd5aed4SZhaoQi 739dd5aed4SZhaoQi struct RelaxAux { 749dd5aed4SZhaoQi DenseMap<Block *, BlockRelaxAux> Blocks; 759dd5aed4SZhaoQi }; 769dd5aed4SZhaoQi 779dd5aed4SZhaoQi } // namespace 789dd5aed4SZhaoQi 799dd5aed4SZhaoQi static bool shouldRelax(const Section &S) { 809dd5aed4SZhaoQi return (S.getMemProt() & orc::MemProt::Exec) != orc::MemProt::None; 819dd5aed4SZhaoQi } 829dd5aed4SZhaoQi 839dd5aed4SZhaoQi static bool isRelaxable(const Edge &E) { 849dd5aed4SZhaoQi switch (E.getKind()) { 859dd5aed4SZhaoQi default: 869dd5aed4SZhaoQi return false; 879dd5aed4SZhaoQi case AlignRelaxable: 889dd5aed4SZhaoQi return true; 899dd5aed4SZhaoQi } 909dd5aed4SZhaoQi } 919dd5aed4SZhaoQi 929dd5aed4SZhaoQi static RelaxAux initRelaxAux(LinkGraph &G) { 939dd5aed4SZhaoQi RelaxAux Aux; 949dd5aed4SZhaoQi for (auto &S : G.sections()) { 959dd5aed4SZhaoQi if (!shouldRelax(S)) 969dd5aed4SZhaoQi continue; 979dd5aed4SZhaoQi for (auto *B : S.blocks()) { 989dd5aed4SZhaoQi auto BlockEmplaceResult = Aux.Blocks.try_emplace(B); 999dd5aed4SZhaoQi assert(BlockEmplaceResult.second && "Block encountered twice"); 1009dd5aed4SZhaoQi auto &BlockAux = BlockEmplaceResult.first->second; 1019dd5aed4SZhaoQi 1029dd5aed4SZhaoQi for (auto &E : B->edges()) 1039dd5aed4SZhaoQi if (isRelaxable(E)) 1049dd5aed4SZhaoQi BlockAux.RelaxEdges.push_back(&E); 1059dd5aed4SZhaoQi 1069dd5aed4SZhaoQi if (BlockAux.RelaxEdges.empty()) { 1079dd5aed4SZhaoQi Aux.Blocks.erase(BlockEmplaceResult.first); 1089dd5aed4SZhaoQi continue; 1099dd5aed4SZhaoQi } 1109dd5aed4SZhaoQi 1119dd5aed4SZhaoQi const auto NumEdges = BlockAux.RelaxEdges.size(); 1129dd5aed4SZhaoQi BlockAux.RelocDeltas.resize(NumEdges, 0); 1139dd5aed4SZhaoQi BlockAux.EdgeKinds.resize_for_overwrite(NumEdges); 1149dd5aed4SZhaoQi 1159dd5aed4SZhaoQi // Store anchors (offset and offset+size) for symbols. 1169dd5aed4SZhaoQi for (auto *Sym : S.symbols()) { 1179dd5aed4SZhaoQi if (!Sym->isDefined() || &Sym->getBlock() != B) 1189dd5aed4SZhaoQi continue; 1199dd5aed4SZhaoQi 1209dd5aed4SZhaoQi BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false}); 1219dd5aed4SZhaoQi BlockAux.Anchors.push_back( 1229dd5aed4SZhaoQi {Sym->getOffset() + Sym->getSize(), Sym, true}); 1239dd5aed4SZhaoQi } 1249dd5aed4SZhaoQi } 1259dd5aed4SZhaoQi } 1269dd5aed4SZhaoQi 1279dd5aed4SZhaoQi // Sort anchors by offset so that we can find the closest relocation 1289dd5aed4SZhaoQi // efficiently. For a zero size symbol, ensure that its start anchor precedes 1299dd5aed4SZhaoQi // its end anchor. For two symbols with anchors at the same offset, their 1309dd5aed4SZhaoQi // order does not matter. 1319dd5aed4SZhaoQi for (auto &BlockAuxIter : Aux.Blocks) { 1329dd5aed4SZhaoQi llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) { 1339dd5aed4SZhaoQi return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End); 1349dd5aed4SZhaoQi }); 1359dd5aed4SZhaoQi } 1369dd5aed4SZhaoQi 1379dd5aed4SZhaoQi return Aux; 1389dd5aed4SZhaoQi } 1399dd5aed4SZhaoQi 1409dd5aed4SZhaoQi static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove, 1419dd5aed4SZhaoQi Edge::Kind &NewEdgeKind) { 1429dd5aed4SZhaoQi const uint64_t Addend = 1439dd5aed4SZhaoQi !E.getTarget().isDefined() ? Log2_64(E.getAddend()) + 1 : E.getAddend(); 1449dd5aed4SZhaoQi const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4; 1459dd5aed4SZhaoQi const uint64_t Align = 1ULL << (Addend & 0xff); 1469dd5aed4SZhaoQi const uint64_t MaxBytes = Addend >> 8; 1479dd5aed4SZhaoQi const uint64_t Off = Loc.getValue() & (Align - 1); 1489dd5aed4SZhaoQi const uint64_t CurBytes = Off == 0 ? 0 : Align - Off; 1499dd5aed4SZhaoQi // All bytes beyond the alignment boundary should be removed. 1509dd5aed4SZhaoQi // If emit bytes more than max bytes to emit, remove all. 1519dd5aed4SZhaoQi if (MaxBytes != 0 && CurBytes > MaxBytes) 1529dd5aed4SZhaoQi Remove = AllBytes; 1539dd5aed4SZhaoQi else 1549dd5aed4SZhaoQi Remove = AllBytes - CurBytes; 1559dd5aed4SZhaoQi 1569dd5aed4SZhaoQi assert(static_cast<int32_t>(Remove) >= 0 && 1579dd5aed4SZhaoQi "R_LARCH_ALIGN needs expanding the content"); 1589dd5aed4SZhaoQi NewEdgeKind = AlignRelaxable; 1599dd5aed4SZhaoQi } 1609dd5aed4SZhaoQi 1619dd5aed4SZhaoQi static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) { 1629dd5aed4SZhaoQi const auto BlockAddr = Block.getAddress(); 1639dd5aed4SZhaoQi bool Changed = false; 1649dd5aed4SZhaoQi ArrayRef<SymbolAnchor> SA = ArrayRef(Aux.Anchors); 1659dd5aed4SZhaoQi uint32_t Delta = 0; 1669dd5aed4SZhaoQi 1679dd5aed4SZhaoQi Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid); 1689dd5aed4SZhaoQi Aux.Writes.clear(); 1699dd5aed4SZhaoQi 1709dd5aed4SZhaoQi for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) { 1719dd5aed4SZhaoQi const auto Loc = BlockAddr + E->getOffset() - Delta; 1729dd5aed4SZhaoQi auto &Cur = Aux.RelocDeltas[I]; 1739dd5aed4SZhaoQi uint32_t Remove = 0; 1749dd5aed4SZhaoQi switch (E->getKind()) { 1759dd5aed4SZhaoQi case AlignRelaxable: 1769dd5aed4SZhaoQi relaxAlign(Loc, *E, Remove, Aux.EdgeKinds[I]); 1779dd5aed4SZhaoQi break; 1789dd5aed4SZhaoQi default: 1799dd5aed4SZhaoQi llvm_unreachable("Unexpected relaxable edge kind"); 1809dd5aed4SZhaoQi } 1819dd5aed4SZhaoQi 1829dd5aed4SZhaoQi // For all anchors whose offsets are <= E->getOffset(), they are preceded by 1839dd5aed4SZhaoQi // the previous relocation whose RelocDeltas value equals Delta. 1849dd5aed4SZhaoQi // Decrease their offset and update their size. 1859dd5aed4SZhaoQi for (; SA.size() && SA[0].Offset <= E->getOffset(); SA = SA.slice(1)) { 1869dd5aed4SZhaoQi if (SA[0].End) 1879dd5aed4SZhaoQi SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset()); 1889dd5aed4SZhaoQi else 1899dd5aed4SZhaoQi SA[0].Sym->setOffset(SA[0].Offset - Delta); 1909dd5aed4SZhaoQi } 1919dd5aed4SZhaoQi 1929dd5aed4SZhaoQi Delta += Remove; 1939dd5aed4SZhaoQi if (Delta != Cur) { 1949dd5aed4SZhaoQi Cur = Delta; 1959dd5aed4SZhaoQi Changed = true; 1969dd5aed4SZhaoQi } 1979dd5aed4SZhaoQi } 1989dd5aed4SZhaoQi 1999dd5aed4SZhaoQi for (const SymbolAnchor &A : SA) { 2009dd5aed4SZhaoQi if (A.End) 2019dd5aed4SZhaoQi A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset()); 2029dd5aed4SZhaoQi else 2039dd5aed4SZhaoQi A.Sym->setOffset(A.Offset - Delta); 2049dd5aed4SZhaoQi } 2059dd5aed4SZhaoQi 2069dd5aed4SZhaoQi return Changed; 2079dd5aed4SZhaoQi } 2089dd5aed4SZhaoQi 2099dd5aed4SZhaoQi static bool relaxOnce(LinkGraph &G, RelaxAux &Aux) { 2109dd5aed4SZhaoQi bool Changed = false; 2119dd5aed4SZhaoQi 2129dd5aed4SZhaoQi for (auto &[B, BlockAux] : Aux.Blocks) 2139dd5aed4SZhaoQi Changed |= relaxBlock(G, *B, BlockAux); 2149dd5aed4SZhaoQi 2159dd5aed4SZhaoQi return Changed; 2169dd5aed4SZhaoQi } 2179dd5aed4SZhaoQi 2189dd5aed4SZhaoQi static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) { 2199dd5aed4SZhaoQi auto Contents = Block.getAlreadyMutableContent(); 2209dd5aed4SZhaoQi auto *Dest = Contents.data(); 2219dd5aed4SZhaoQi uint32_t Offset = 0; 2229dd5aed4SZhaoQi uint32_t Delta = 0; 2239dd5aed4SZhaoQi 2249dd5aed4SZhaoQi // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite 2259dd5aed4SZhaoQi // instructions for relaxed relocations. 2269dd5aed4SZhaoQi for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) { 2279dd5aed4SZhaoQi uint32_t Remove = Aux.RelocDeltas[I] - Delta; 2289dd5aed4SZhaoQi Delta = Aux.RelocDeltas[I]; 2299dd5aed4SZhaoQi if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid) 2309dd5aed4SZhaoQi continue; 2319dd5aed4SZhaoQi 2329dd5aed4SZhaoQi // Copy from last location to the current relocated location. 2339dd5aed4SZhaoQi const auto Size = E->getOffset() - Offset; 2349dd5aed4SZhaoQi std::memmove(Dest, Contents.data() + Offset, Size); 2359dd5aed4SZhaoQi Dest += Size; 2369dd5aed4SZhaoQi Offset = E->getOffset() + Remove; 2379dd5aed4SZhaoQi } 2389dd5aed4SZhaoQi 2399dd5aed4SZhaoQi std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset); 2409dd5aed4SZhaoQi 2419dd5aed4SZhaoQi // Fixup edge offsets and kinds. 2429dd5aed4SZhaoQi Delta = 0; 2439dd5aed4SZhaoQi size_t I = 0; 2449dd5aed4SZhaoQi for (auto &E : Block.edges()) { 2459dd5aed4SZhaoQi E.setOffset(E.getOffset() - Delta); 2469dd5aed4SZhaoQi 2479dd5aed4SZhaoQi if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) { 2489dd5aed4SZhaoQi if (Aux.EdgeKinds[I] != Edge::Invalid) 2499dd5aed4SZhaoQi E.setKind(Aux.EdgeKinds[I]); 2509dd5aed4SZhaoQi 2519dd5aed4SZhaoQi Delta = Aux.RelocDeltas[I]; 2529dd5aed4SZhaoQi ++I; 2539dd5aed4SZhaoQi } 2549dd5aed4SZhaoQi } 2559dd5aed4SZhaoQi 2569dd5aed4SZhaoQi // Remove AlignRelaxable edges: all other relaxable edges got modified and 2579dd5aed4SZhaoQi // will be used later while linking. Alignment is entirely handled here so we 2589dd5aed4SZhaoQi // don't need these edges anymore. 2599dd5aed4SZhaoQi for (auto IE = Block.edges().begin(); IE != Block.edges().end();) { 2609dd5aed4SZhaoQi if (IE->getKind() == AlignRelaxable) 2619dd5aed4SZhaoQi IE = Block.removeEdge(IE); 2629dd5aed4SZhaoQi else 2639dd5aed4SZhaoQi ++IE; 2649dd5aed4SZhaoQi } 2659dd5aed4SZhaoQi } 2669dd5aed4SZhaoQi 2679dd5aed4SZhaoQi static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) { 2689dd5aed4SZhaoQi for (auto &[B, BlockAux] : Aux.Blocks) 2699dd5aed4SZhaoQi finalizeBlockRelax(G, *B, BlockAux); 2709dd5aed4SZhaoQi } 2719dd5aed4SZhaoQi 2729dd5aed4SZhaoQi static Error relax(LinkGraph &G) { 2739dd5aed4SZhaoQi auto Aux = initRelaxAux(G); 2749dd5aed4SZhaoQi while (relaxOnce(G, Aux)) { 2759dd5aed4SZhaoQi } 2769dd5aed4SZhaoQi finalizeRelax(G, Aux); 2779dd5aed4SZhaoQi return Error::success(); 2789dd5aed4SZhaoQi } 2799dd5aed4SZhaoQi 280f10d452dSwanglei template <typename ELFT> 281f10d452dSwanglei class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> { 282f10d452dSwanglei private: 283f10d452dSwanglei static Expected<loongarch::EdgeKind_loongarch> 284f10d452dSwanglei getRelocationKind(const uint32_t Type) { 285f10d452dSwanglei using namespace loongarch; 286f10d452dSwanglei switch (Type) { 287f10d452dSwanglei case ELF::R_LARCH_64: 288f10d452dSwanglei return Pointer64; 289f10d452dSwanglei case ELF::R_LARCH_32: 290f10d452dSwanglei return Pointer32; 291f10d452dSwanglei case ELF::R_LARCH_32_PCREL: 292f10d452dSwanglei return Delta32; 2934c5c5e2fSZhaoQi case ELF::R_LARCH_B16: 2944c5c5e2fSZhaoQi return Branch16PCRel; 2954c5c5e2fSZhaoQi case ELF::R_LARCH_B21: 2964c5c5e2fSZhaoQi return Branch21PCRel; 297f10d452dSwanglei case ELF::R_LARCH_B26: 298f10d452dSwanglei return Branch26PCRel; 299f10d452dSwanglei case ELF::R_LARCH_PCALA_HI20: 300f10d452dSwanglei return Page20; 301f10d452dSwanglei case ELF::R_LARCH_PCALA_LO12: 302f10d452dSwanglei return PageOffset12; 303f10d452dSwanglei case ELF::R_LARCH_GOT_PC_HI20: 304f10d452dSwanglei return RequestGOTAndTransformToPage20; 305f10d452dSwanglei case ELF::R_LARCH_GOT_PC_LO12: 306f10d452dSwanglei return RequestGOTAndTransformToPageOffset12; 307ca9f358bSwanglei case ELF::R_LARCH_CALL36: 308ca9f358bSwanglei return Call36PCRel; 309*f6253f8fSZhaoQi case ELF::R_LARCH_ADD6: 310*f6253f8fSZhaoQi return Add6; 311*f6253f8fSZhaoQi case ELF::R_LARCH_ADD8: 312*f6253f8fSZhaoQi return Add8; 313*f6253f8fSZhaoQi case ELF::R_LARCH_ADD16: 314*f6253f8fSZhaoQi return Add16; 315*f6253f8fSZhaoQi case ELF::R_LARCH_ADD32: 316*f6253f8fSZhaoQi return Add32; 317*f6253f8fSZhaoQi case ELF::R_LARCH_ADD64: 318*f6253f8fSZhaoQi return Add64; 319*f6253f8fSZhaoQi case ELF::R_LARCH_ADD_ULEB128: 320*f6253f8fSZhaoQi return AddUleb128; 321*f6253f8fSZhaoQi case ELF::R_LARCH_SUB6: 322*f6253f8fSZhaoQi return Sub6; 323*f6253f8fSZhaoQi case ELF::R_LARCH_SUB8: 324*f6253f8fSZhaoQi return Sub8; 325*f6253f8fSZhaoQi case ELF::R_LARCH_SUB16: 326*f6253f8fSZhaoQi return Sub16; 327*f6253f8fSZhaoQi case ELF::R_LARCH_SUB32: 328*f6253f8fSZhaoQi return Sub32; 329*f6253f8fSZhaoQi case ELF::R_LARCH_SUB64: 330*f6253f8fSZhaoQi return Sub64; 331*f6253f8fSZhaoQi case ELF::R_LARCH_SUB_ULEB128: 332*f6253f8fSZhaoQi return SubUleb128; 3339dd5aed4SZhaoQi case ELF::R_LARCH_ALIGN: 3349dd5aed4SZhaoQi return AlignRelaxable; 335f10d452dSwanglei } 336f10d452dSwanglei 337f10d452dSwanglei return make_error<JITLinkError>( 338f10d452dSwanglei "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) + 339f10d452dSwanglei object::getELFRelocationTypeName(ELF::EM_LOONGARCH, Type)); 340f10d452dSwanglei } 341f10d452dSwanglei 3429dd5aed4SZhaoQi EdgeKind_loongarch getRelaxableRelocationKind(EdgeKind_loongarch Kind) { 3439dd5aed4SZhaoQi // TODO: Implement more. Just ignore all relaxations now. 3449dd5aed4SZhaoQi return Kind; 3459dd5aed4SZhaoQi } 3469dd5aed4SZhaoQi 347f10d452dSwanglei Error addRelocations() override { 348f10d452dSwanglei LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 349f10d452dSwanglei 350f10d452dSwanglei using Base = ELFLinkGraphBuilder<ELFT>; 351f10d452dSwanglei using Self = ELFLinkGraphBuilder_loongarch<ELFT>; 352f10d452dSwanglei for (const auto &RelSect : Base::Sections) 353f10d452dSwanglei if (Error Err = Base::forEachRelaRelocation(RelSect, this, 354f10d452dSwanglei &Self::addSingleRelocation)) 355f10d452dSwanglei return Err; 356f10d452dSwanglei 357f10d452dSwanglei return Error::success(); 358f10d452dSwanglei } 359f10d452dSwanglei 360f10d452dSwanglei Error addSingleRelocation(const typename ELFT::Rela &Rel, 361f10d452dSwanglei const typename ELFT::Shdr &FixupSect, 362f10d452dSwanglei Block &BlockToFix) { 363f10d452dSwanglei using Base = ELFLinkGraphBuilder<ELFT>; 364f10d452dSwanglei 3659dd5aed4SZhaoQi uint32_t Type = Rel.getType(false); 3669dd5aed4SZhaoQi int64_t Addend = Rel.r_addend; 3679dd5aed4SZhaoQi 3689dd5aed4SZhaoQi if (Type == ELF::R_LARCH_RELAX) { 3699dd5aed4SZhaoQi if (BlockToFix.edges_empty()) 3709dd5aed4SZhaoQi return make_error<StringError>( 3719dd5aed4SZhaoQi "R_LARCH_RELAX without preceding relocation", 3729dd5aed4SZhaoQi inconvertibleErrorCode()); 3739dd5aed4SZhaoQi 3749dd5aed4SZhaoQi auto &PrevEdge = *std::prev(BlockToFix.edges().end()); 3759dd5aed4SZhaoQi auto Kind = static_cast<EdgeKind_loongarch>(PrevEdge.getKind()); 3769dd5aed4SZhaoQi PrevEdge.setKind(getRelaxableRelocationKind(Kind)); 3779dd5aed4SZhaoQi return Error::success(); 3789dd5aed4SZhaoQi } 3799dd5aed4SZhaoQi 3809dd5aed4SZhaoQi Expected<loongarch::EdgeKind_loongarch> Kind = getRelocationKind(Type); 3819dd5aed4SZhaoQi if (!Kind) 3829dd5aed4SZhaoQi return Kind.takeError(); 3839dd5aed4SZhaoQi 384f10d452dSwanglei uint32_t SymbolIndex = Rel.getSymbol(false); 385f10d452dSwanglei auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 386f10d452dSwanglei if (!ObjSymbol) 387f10d452dSwanglei return ObjSymbol.takeError(); 388f10d452dSwanglei 389f10d452dSwanglei Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 390f10d452dSwanglei if (!GraphSymbol) 391f10d452dSwanglei return make_error<StringError>( 392f10d452dSwanglei formatv("Could not find symbol at given index, did you add it to " 393f10d452dSwanglei "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 394f10d452dSwanglei SymbolIndex, (*ObjSymbol)->st_shndx, 395f10d452dSwanglei Base::GraphSymbols.size()), 396f10d452dSwanglei inconvertibleErrorCode()); 397f10d452dSwanglei 398f10d452dSwanglei auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; 399f10d452dSwanglei Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 400f10d452dSwanglei Edge GE(*Kind, Offset, *GraphSymbol, Addend); 401f10d452dSwanglei LLVM_DEBUG({ 402f10d452dSwanglei dbgs() << " "; 403f10d452dSwanglei printEdge(dbgs(), BlockToFix, GE, loongarch::getEdgeKindName(*Kind)); 404f10d452dSwanglei dbgs() << "\n"; 405f10d452dSwanglei }); 406f10d452dSwanglei 407f10d452dSwanglei BlockToFix.addEdge(std::move(GE)); 408f10d452dSwanglei 409f10d452dSwanglei return Error::success(); 410f10d452dSwanglei } 411f10d452dSwanglei 412f10d452dSwanglei public: 413f10d452dSwanglei ELFLinkGraphBuilder_loongarch(StringRef FileName, 4142ccf7ed2SJared Wyles const object::ELFFile<ELFT> &Obj, 4152ccf7ed2SJared Wyles std::shared_ptr<orc::SymbolStringPool> SSP, 4162ccf7ed2SJared Wyles Triple TT, SubtargetFeatures Features) 4172ccf7ed2SJared Wyles : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT), 4182ccf7ed2SJared Wyles std::move(Features), FileName, 4192ccf7ed2SJared Wyles loongarch::getEdgeKindName) {} 420f10d452dSwanglei }; 421f10d452dSwanglei 422f10d452dSwanglei Error buildTables_ELF_loongarch(LinkGraph &G) { 423f10d452dSwanglei LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); 424f10d452dSwanglei 425f10d452dSwanglei GOTTableManager GOT; 426f10d452dSwanglei PLTTableManager PLT(GOT); 427f10d452dSwanglei visitExistingEdges(G, GOT, PLT); 428f10d452dSwanglei return Error::success(); 429f10d452dSwanglei } 430f10d452dSwanglei 431f10d452dSwanglei } // namespace 432f10d452dSwanglei 433f10d452dSwanglei namespace llvm { 434f10d452dSwanglei namespace jitlink { 435f10d452dSwanglei 4362ccf7ed2SJared Wyles Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_loongarch( 4372ccf7ed2SJared Wyles MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { 438f10d452dSwanglei LLVM_DEBUG({ 439f10d452dSwanglei dbgs() << "Building jitlink graph for new input " 440f10d452dSwanglei << ObjectBuffer.getBufferIdentifier() << "...\n"; 441f10d452dSwanglei }); 442f10d452dSwanglei 443f10d452dSwanglei auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 444f10d452dSwanglei if (!ELFObj) 445f10d452dSwanglei return ELFObj.takeError(); 446f10d452dSwanglei 447348d0a6bSJob Noorman auto Features = (*ELFObj)->getFeatures(); 448348d0a6bSJob Noorman if (!Features) 449348d0a6bSJob Noorman return Features.takeError(); 450348d0a6bSJob Noorman 451f10d452dSwanglei if ((*ELFObj)->getArch() == Triple::loongarch64) { 452f10d452dSwanglei auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 453f10d452dSwanglei return ELFLinkGraphBuilder_loongarch<object::ELF64LE>( 454f10d452dSwanglei (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 4552ccf7ed2SJared Wyles std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features)) 456f10d452dSwanglei .buildGraph(); 457f10d452dSwanglei } 458f10d452dSwanglei 459f10d452dSwanglei assert((*ELFObj)->getArch() == Triple::loongarch32 && 460f10d452dSwanglei "Invalid triple for LoongArch ELF object file"); 461f10d452dSwanglei auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj); 462f10d452dSwanglei return ELFLinkGraphBuilder_loongarch<object::ELF32LE>( 4632ccf7ed2SJared Wyles (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP), 46452b88457SJob Noorman (*ELFObj)->makeTriple(), std::move(*Features)) 465f10d452dSwanglei .buildGraph(); 466f10d452dSwanglei } 467f10d452dSwanglei 468f10d452dSwanglei void link_ELF_loongarch(std::unique_ptr<LinkGraph> G, 469f10d452dSwanglei std::unique_ptr<JITLinkContext> Ctx) { 470f10d452dSwanglei PassConfiguration Config; 471f10d452dSwanglei const Triple &TT = G->getTargetTriple(); 472f10d452dSwanglei if (Ctx->shouldAddDefaultTargetPasses(TT)) { 47394239712SEymen Ünay // Add eh-frame passes. 474f10d452dSwanglei Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); 475f10d452dSwanglei Config.PrePrunePasses.push_back( 476f10d452dSwanglei EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64, 477f10d452dSwanglei Delta32, Delta64, NegDelta32)); 478f10d452dSwanglei Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame")); 479f10d452dSwanglei 480f10d452dSwanglei // Add a mark-live pass. 481f10d452dSwanglei if (auto MarkLive = Ctx->getMarkLivePass(TT)) 482f10d452dSwanglei Config.PrePrunePasses.push_back(std::move(MarkLive)); 483f10d452dSwanglei else 484f10d452dSwanglei Config.PrePrunePasses.push_back(markAllSymbolsLive); 485f10d452dSwanglei 486f10d452dSwanglei // Add an in-place GOT/PLTStubs build pass. 487f10d452dSwanglei Config.PostPrunePasses.push_back(buildTables_ELF_loongarch); 4889dd5aed4SZhaoQi 4899dd5aed4SZhaoQi // Add a linker relaxation pass. 4909dd5aed4SZhaoQi Config.PostAllocationPasses.push_back(relax); 491f10d452dSwanglei } 492f10d452dSwanglei 493f10d452dSwanglei if (auto Err = Ctx->modifyPassConfig(*G, Config)) 494f10d452dSwanglei return Ctx->notifyFailed(std::move(Err)); 495f10d452dSwanglei 496f10d452dSwanglei ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config)); 497f10d452dSwanglei } 498f10d452dSwanglei 4999dd5aed4SZhaoQi LinkGraphPassFunction createRelaxationPass_ELF_loongarch() { return relax; } 5009dd5aed4SZhaoQi 501f10d452dSwanglei } // namespace jitlink 502f10d452dSwanglei } // namespace llvm 503