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