1 //===----- ELF_aarch64.cpp - JIT linker implementation for ELF/aarch64 ----===// 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/aarch64 jit-link implementation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h" 14 #include "ELFLinkGraphBuilder.h" 15 #include "JITLinkGeneric.h" 16 #include "llvm/BinaryFormat/ELF.h" 17 #include "llvm/ExecutionEngine/JITLink/aarch64.h" 18 #include "llvm/Object/ELFObjectFile.h" 19 #include "llvm/Support/MathExtras.h" 20 21 #define DEBUG_TYPE "jitlink" 22 23 using namespace llvm; 24 using namespace llvm::jitlink; 25 26 namespace llvm { 27 namespace jitlink { 28 29 class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> { 30 friend class JITLinker<ELFJITLinker_aarch64>; 31 32 public: 33 ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx, 34 std::unique_ptr<LinkGraph> G, 35 PassConfiguration PassConfig) 36 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 37 38 private: 39 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 40 return aarch64::applyFixup(G, B, E); 41 } 42 }; 43 44 template <typename ELFT> 45 class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> { 46 private: 47 enum ELFAArch64RelocationKind : Edge::Kind { 48 ELFBranch26 = Edge::FirstRelocation, 49 }; 50 51 static Expected<ELFAArch64RelocationKind> 52 getRelocationKind(const uint32_t Type) { 53 using namespace aarch64; 54 switch (Type) { 55 case ELF::R_AARCH64_CALL26: 56 return ELFBranch26; 57 } 58 59 return make_error<JITLinkError>("Unsupported aarch64 relocation:" + 60 formatv("{0:d}", Type)); 61 } 62 63 Error addRelocations() override { 64 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 65 66 using Base = ELFLinkGraphBuilder<ELFT>; 67 using Self = ELFLinkGraphBuilder_aarch64<ELFT>; 68 for (const auto &RelSect : Base::Sections) 69 if (Error Err = Base::forEachRelocation(RelSect, this, 70 &Self::addSingleRelocation)) 71 return Err; 72 73 return Error::success(); 74 } 75 76 Error addSingleRelocation(const typename ELFT::Rela &Rel, 77 const typename ELFT::Shdr &FixupSect, 78 Block &BlockToFix) { 79 using Base = ELFLinkGraphBuilder<ELFT>; 80 81 uint32_t SymbolIndex = Rel.getSymbol(false); 82 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 83 if (!ObjSymbol) 84 return ObjSymbol.takeError(); 85 86 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 87 if (!GraphSymbol) 88 return make_error<StringError>( 89 formatv("Could not find symbol at given index, did you add it to " 90 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 91 SymbolIndex, (*ObjSymbol)->st_shndx, 92 Base::GraphSymbols.size()), 93 inconvertibleErrorCode()); 94 95 uint32_t Type = Rel.getType(false); 96 Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type); 97 if (!RelocKind) 98 return RelocKind.takeError(); 99 100 int64_t Addend = Rel.r_addend; 101 orc::ExecutorAddr FixupAddress = 102 orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; 103 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 104 105 Edge::Kind Kind = Edge::Invalid; 106 107 switch (*RelocKind) { 108 case ELFBranch26: { 109 Kind = aarch64::Branch26; 110 break; 111 } 112 }; 113 114 Edge GE(Kind, Offset, *GraphSymbol, Addend); 115 LLVM_DEBUG({ 116 dbgs() << " "; 117 printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind)); 118 dbgs() << "\n"; 119 }); 120 121 BlockToFix.addEdge(std::move(GE)); 122 return Error::success(); 123 } 124 125 /// Return the string name of the given ELF aarch64 edge kind. 126 const char *getELFAArch64RelocationKindName(Edge::Kind R) { 127 switch (R) { 128 case ELFBranch26: 129 return "ELFBranch26"; 130 default: 131 return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); 132 } 133 } 134 135 public: 136 ELFLinkGraphBuilder_aarch64(StringRef FileName, 137 const object::ELFFile<ELFT> &Obj, const Triple T) 138 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName, 139 aarch64::getEdgeKindName) {} 140 }; 141 142 Expected<std::unique_ptr<LinkGraph>> 143 createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) { 144 LLVM_DEBUG({ 145 dbgs() << "Building jitlink graph for new input " 146 << ObjectBuffer.getBufferIdentifier() << "...\n"; 147 }); 148 149 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 150 if (!ELFObj) 151 return ELFObj.takeError(); 152 153 assert((*ELFObj)->getArch() == Triple::aarch64 && 154 "Only AArch64 (little endian) is supported for now"); 155 156 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 157 return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(), 158 ELFObjFile.getELFFile(), 159 (*ELFObj)->makeTriple()) 160 .buildGraph(); 161 } 162 163 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G, 164 std::unique_ptr<JITLinkContext> Ctx) { 165 PassConfiguration Config; 166 const Triple &TT = G->getTargetTriple(); 167 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 168 if (auto MarkLive = Ctx->getMarkLivePass(TT)) 169 Config.PrePrunePasses.push_back(std::move(MarkLive)); 170 else 171 Config.PrePrunePasses.push_back(markAllSymbolsLive); 172 } 173 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 174 return Ctx->notifyFailed(std::move(Err)); 175 176 ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config)); 177 } 178 179 } // namespace jitlink 180 } // namespace llvm 181