1bdd1243dSDimitry Andric //===--- ELF_loongarch.cpp - JIT linker implementation for ELF/loongarch --===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric // ELF/loongarch jit-link implementation. 10bdd1243dSDimitry Andric // 11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12bdd1243dSDimitry Andric 13bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h" 14bdd1243dSDimitry Andric #include "llvm/BinaryFormat/ELF.h" 15bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" 16bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 17bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/loongarch.h" 18bdd1243dSDimitry Andric #include "llvm/Object/ELF.h" 19bdd1243dSDimitry Andric #include "llvm/Object/ELFObjectFile.h" 20bdd1243dSDimitry Andric 21bdd1243dSDimitry Andric #include "EHFrameSupportImpl.h" 22bdd1243dSDimitry Andric #include "ELFLinkGraphBuilder.h" 23bdd1243dSDimitry Andric #include "JITLinkGeneric.h" 24bdd1243dSDimitry Andric 25bdd1243dSDimitry Andric #define DEBUG_TYPE "jitlink" 26bdd1243dSDimitry Andric 27bdd1243dSDimitry Andric using namespace llvm; 28bdd1243dSDimitry Andric using namespace llvm::jitlink; 29bdd1243dSDimitry Andric using namespace llvm::jitlink::loongarch; 30bdd1243dSDimitry Andric 31bdd1243dSDimitry Andric namespace { 32bdd1243dSDimitry Andric 33bdd1243dSDimitry Andric class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> { 34bdd1243dSDimitry Andric friend class JITLinker<ELFJITLinker_loongarch>; 35bdd1243dSDimitry Andric 36bdd1243dSDimitry Andric public: 37bdd1243dSDimitry Andric ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx, 38bdd1243dSDimitry Andric std::unique_ptr<LinkGraph> G, 39bdd1243dSDimitry Andric PassConfiguration PassConfig) 40bdd1243dSDimitry Andric : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 41bdd1243dSDimitry Andric 42bdd1243dSDimitry Andric private: 43bdd1243dSDimitry Andric Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 44bdd1243dSDimitry Andric return loongarch::applyFixup(G, B, E); 45bdd1243dSDimitry Andric } 46bdd1243dSDimitry Andric }; 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric template <typename ELFT> 49bdd1243dSDimitry Andric class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> { 50bdd1243dSDimitry Andric private: 51bdd1243dSDimitry Andric static Expected<loongarch::EdgeKind_loongarch> 52bdd1243dSDimitry Andric getRelocationKind(const uint32_t Type) { 53bdd1243dSDimitry Andric using namespace loongarch; 54bdd1243dSDimitry Andric switch (Type) { 55bdd1243dSDimitry Andric case ELF::R_LARCH_64: 56bdd1243dSDimitry Andric return Pointer64; 57bdd1243dSDimitry Andric case ELF::R_LARCH_32: 58bdd1243dSDimitry Andric return Pointer32; 59bdd1243dSDimitry Andric case ELF::R_LARCH_32_PCREL: 60bdd1243dSDimitry Andric return Delta32; 61bdd1243dSDimitry Andric case ELF::R_LARCH_B26: 62bdd1243dSDimitry Andric return Branch26PCRel; 63bdd1243dSDimitry Andric case ELF::R_LARCH_PCALA_HI20: 64bdd1243dSDimitry Andric return Page20; 65bdd1243dSDimitry Andric case ELF::R_LARCH_PCALA_LO12: 66bdd1243dSDimitry Andric return PageOffset12; 67bdd1243dSDimitry Andric case ELF::R_LARCH_GOT_PC_HI20: 68bdd1243dSDimitry Andric return RequestGOTAndTransformToPage20; 69bdd1243dSDimitry Andric case ELF::R_LARCH_GOT_PC_LO12: 70bdd1243dSDimitry Andric return RequestGOTAndTransformToPageOffset12; 71bdd1243dSDimitry Andric } 72bdd1243dSDimitry Andric 73bdd1243dSDimitry Andric return make_error<JITLinkError>( 74bdd1243dSDimitry Andric "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) + 75bdd1243dSDimitry Andric object::getELFRelocationTypeName(ELF::EM_LOONGARCH, Type)); 76bdd1243dSDimitry Andric } 77bdd1243dSDimitry Andric 78bdd1243dSDimitry Andric Error addRelocations() override { 79bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 80bdd1243dSDimitry Andric 81bdd1243dSDimitry Andric using Base = ELFLinkGraphBuilder<ELFT>; 82bdd1243dSDimitry Andric using Self = ELFLinkGraphBuilder_loongarch<ELFT>; 83bdd1243dSDimitry Andric for (const auto &RelSect : Base::Sections) 84bdd1243dSDimitry Andric if (Error Err = Base::forEachRelaRelocation(RelSect, this, 85bdd1243dSDimitry Andric &Self::addSingleRelocation)) 86bdd1243dSDimitry Andric return Err; 87bdd1243dSDimitry Andric 88bdd1243dSDimitry Andric return Error::success(); 89bdd1243dSDimitry Andric } 90bdd1243dSDimitry Andric 91bdd1243dSDimitry Andric Error addSingleRelocation(const typename ELFT::Rela &Rel, 92bdd1243dSDimitry Andric const typename ELFT::Shdr &FixupSect, 93bdd1243dSDimitry Andric Block &BlockToFix) { 94bdd1243dSDimitry Andric using Base = ELFLinkGraphBuilder<ELFT>; 95bdd1243dSDimitry Andric 96bdd1243dSDimitry Andric uint32_t SymbolIndex = Rel.getSymbol(false); 97bdd1243dSDimitry Andric auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 98bdd1243dSDimitry Andric if (!ObjSymbol) 99bdd1243dSDimitry Andric return ObjSymbol.takeError(); 100bdd1243dSDimitry Andric 101bdd1243dSDimitry Andric Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 102bdd1243dSDimitry Andric if (!GraphSymbol) 103bdd1243dSDimitry Andric return make_error<StringError>( 104bdd1243dSDimitry Andric formatv("Could not find symbol at given index, did you add it to " 105bdd1243dSDimitry Andric "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 106bdd1243dSDimitry Andric SymbolIndex, (*ObjSymbol)->st_shndx, 107bdd1243dSDimitry Andric Base::GraphSymbols.size()), 108bdd1243dSDimitry Andric inconvertibleErrorCode()); 109bdd1243dSDimitry Andric 110bdd1243dSDimitry Andric uint32_t Type = Rel.getType(false); 111bdd1243dSDimitry Andric Expected<loongarch::EdgeKind_loongarch> Kind = getRelocationKind(Type); 112bdd1243dSDimitry Andric if (!Kind) 113bdd1243dSDimitry Andric return Kind.takeError(); 114bdd1243dSDimitry Andric 115bdd1243dSDimitry Andric int64_t Addend = Rel.r_addend; 116bdd1243dSDimitry Andric auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; 117bdd1243dSDimitry Andric Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 118bdd1243dSDimitry Andric Edge GE(*Kind, Offset, *GraphSymbol, Addend); 119bdd1243dSDimitry Andric LLVM_DEBUG({ 120bdd1243dSDimitry Andric dbgs() << " "; 121bdd1243dSDimitry Andric printEdge(dbgs(), BlockToFix, GE, loongarch::getEdgeKindName(*Kind)); 122bdd1243dSDimitry Andric dbgs() << "\n"; 123bdd1243dSDimitry Andric }); 124bdd1243dSDimitry Andric 125bdd1243dSDimitry Andric BlockToFix.addEdge(std::move(GE)); 126bdd1243dSDimitry Andric 127bdd1243dSDimitry Andric return Error::success(); 128bdd1243dSDimitry Andric } 129bdd1243dSDimitry Andric 130bdd1243dSDimitry Andric public: 131bdd1243dSDimitry Andric ELFLinkGraphBuilder_loongarch(StringRef FileName, 13206c3fb27SDimitry Andric const object::ELFFile<ELFT> &Obj, Triple TT, 13306c3fb27SDimitry Andric SubtargetFeatures Features) 13406c3fb27SDimitry Andric : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features), 13506c3fb27SDimitry Andric FileName, loongarch::getEdgeKindName) {} 136bdd1243dSDimitry Andric }; 137bdd1243dSDimitry Andric 138bdd1243dSDimitry Andric Error buildTables_ELF_loongarch(LinkGraph &G) { 139bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric GOTTableManager GOT; 142bdd1243dSDimitry Andric PLTTableManager PLT(GOT); 143bdd1243dSDimitry Andric visitExistingEdges(G, GOT, PLT); 144bdd1243dSDimitry Andric return Error::success(); 145bdd1243dSDimitry Andric } 146bdd1243dSDimitry Andric 147bdd1243dSDimitry Andric } // namespace 148bdd1243dSDimitry Andric 149bdd1243dSDimitry Andric namespace llvm { 150bdd1243dSDimitry Andric namespace jitlink { 151bdd1243dSDimitry Andric 152bdd1243dSDimitry Andric Expected<std::unique_ptr<LinkGraph>> 153bdd1243dSDimitry Andric createLinkGraphFromELFObject_loongarch(MemoryBufferRef ObjectBuffer) { 154bdd1243dSDimitry Andric LLVM_DEBUG({ 155bdd1243dSDimitry Andric dbgs() << "Building jitlink graph for new input " 156bdd1243dSDimitry Andric << ObjectBuffer.getBufferIdentifier() << "...\n"; 157bdd1243dSDimitry Andric }); 158bdd1243dSDimitry Andric 159bdd1243dSDimitry Andric auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 160bdd1243dSDimitry Andric if (!ELFObj) 161bdd1243dSDimitry Andric return ELFObj.takeError(); 162bdd1243dSDimitry Andric 16306c3fb27SDimitry Andric auto Features = (*ELFObj)->getFeatures(); 16406c3fb27SDimitry Andric if (!Features) 16506c3fb27SDimitry Andric return Features.takeError(); 16606c3fb27SDimitry Andric 167bdd1243dSDimitry Andric if ((*ELFObj)->getArch() == Triple::loongarch64) { 168bdd1243dSDimitry Andric auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 169bdd1243dSDimitry Andric return ELFLinkGraphBuilder_loongarch<object::ELF64LE>( 170bdd1243dSDimitry Andric (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 17106c3fb27SDimitry Andric (*ELFObj)->makeTriple(), std::move(*Features)) 172bdd1243dSDimitry Andric .buildGraph(); 173bdd1243dSDimitry Andric } 174bdd1243dSDimitry Andric 175bdd1243dSDimitry Andric assert((*ELFObj)->getArch() == Triple::loongarch32 && 176bdd1243dSDimitry Andric "Invalid triple for LoongArch ELF object file"); 177bdd1243dSDimitry Andric auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj); 178bdd1243dSDimitry Andric return ELFLinkGraphBuilder_loongarch<object::ELF32LE>( 179bdd1243dSDimitry Andric (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 18006c3fb27SDimitry Andric (*ELFObj)->makeTriple(), std::move(*Features)) 181bdd1243dSDimitry Andric .buildGraph(); 182bdd1243dSDimitry Andric } 183bdd1243dSDimitry Andric 184bdd1243dSDimitry Andric void link_ELF_loongarch(std::unique_ptr<LinkGraph> G, 185bdd1243dSDimitry Andric std::unique_ptr<JITLinkContext> Ctx) { 186bdd1243dSDimitry Andric PassConfiguration Config; 187bdd1243dSDimitry Andric const Triple &TT = G->getTargetTriple(); 188bdd1243dSDimitry Andric if (Ctx->shouldAddDefaultTargetPasses(TT)) { 189*5f757f3fSDimitry Andric // Add eh-frame passes. 190bdd1243dSDimitry Andric Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); 191bdd1243dSDimitry Andric Config.PrePrunePasses.push_back( 192bdd1243dSDimitry Andric EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64, 193bdd1243dSDimitry Andric Delta32, Delta64, NegDelta32)); 194bdd1243dSDimitry Andric Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame")); 195bdd1243dSDimitry Andric 196bdd1243dSDimitry Andric // Add a mark-live pass. 197bdd1243dSDimitry Andric if (auto MarkLive = Ctx->getMarkLivePass(TT)) 198bdd1243dSDimitry Andric Config.PrePrunePasses.push_back(std::move(MarkLive)); 199bdd1243dSDimitry Andric else 200bdd1243dSDimitry Andric Config.PrePrunePasses.push_back(markAllSymbolsLive); 201bdd1243dSDimitry Andric 202bdd1243dSDimitry Andric // Add an in-place GOT/PLTStubs build pass. 203bdd1243dSDimitry Andric Config.PostPrunePasses.push_back(buildTables_ELF_loongarch); 204bdd1243dSDimitry Andric } 205bdd1243dSDimitry Andric 206bdd1243dSDimitry Andric if (auto Err = Ctx->modifyPassConfig(*G, Config)) 207bdd1243dSDimitry Andric return Ctx->notifyFailed(std::move(Err)); 208bdd1243dSDimitry Andric 209bdd1243dSDimitry Andric ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config)); 210bdd1243dSDimitry Andric } 211bdd1243dSDimitry Andric 212bdd1243dSDimitry Andric } // namespace jitlink 213bdd1243dSDimitry Andric } // namespace llvm 214