1 //===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===// 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 // COFF/x86_64 jit-link implementation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h" 14 #include "COFFLinkGraphBuilder.h" 15 #include "JITLinkGeneric.h" 16 #include "SEHFrameSupport.h" 17 #include "llvm/BinaryFormat/COFF.h" 18 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 19 #include "llvm/Object/COFF.h" 20 #include "llvm/Support/Endian.h" 21 22 #define DEBUG_TYPE "jitlink" 23 24 using namespace llvm; 25 using namespace llvm::jitlink; 26 27 namespace { 28 29 enum EdgeKind_coff_x86_64 : Edge::Kind { 30 PCRel32 = x86_64::FirstPlatformRelocation, 31 Pointer32NB, 32 }; 33 34 class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> { 35 friend class JITLinker<COFFJITLinker_x86_64>; 36 37 public: 38 COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 39 std::unique_ptr<LinkGraph> G, 40 PassConfiguration PassConfig) 41 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 42 43 private: 44 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 45 return x86_64::applyFixup(G, B, E, nullptr); 46 } 47 }; 48 49 class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder { 50 private: 51 Error addRelocations() override { 52 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 53 54 for (const auto &RelSect : sections()) 55 if (Error Err = COFFLinkGraphBuilder::forEachRelocation( 56 RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation)) 57 return Err; 58 59 return Error::success(); 60 } 61 62 Error addSingleRelocation(const object::RelocationRef &Rel, 63 const object::SectionRef &FixupSect, 64 Block &BlockToFix) { 65 const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel); 66 auto SymbolIt = Rel.getSymbol(); 67 if (SymbolIt == getObject().symbol_end()) { 68 return make_error<StringError>( 69 formatv("Invalid symbol index in relocation entry. " 70 "index: {0}, section: {1}", 71 COFFRel->SymbolTableIndex, FixupSect.getIndex()), 72 inconvertibleErrorCode()); 73 } 74 75 object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt); 76 COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol); 77 78 Symbol *GraphSymbol = getGraphSymbol(SymIndex); 79 if (!GraphSymbol) 80 return make_error<StringError>( 81 formatv("Could not find symbol at given index, did you add it to " 82 "JITSymbolTable? index: {0}, section: {1}", 83 SymIndex, FixupSect.getIndex()), 84 inconvertibleErrorCode()); 85 86 int64_t Addend = 0; 87 orc::ExecutorAddr FixupAddress = 88 orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset(); 89 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 90 91 Edge::Kind Kind = Edge::Invalid; 92 const char *FixupPtr = BlockToFix.getContent().data() + Offset; 93 94 switch (Rel.getType()) { 95 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: { 96 Kind = EdgeKind_coff_x86_64::Pointer32NB; 97 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 98 break; 99 } 100 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: { 101 Kind = EdgeKind_coff_x86_64::PCRel32; 102 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 103 break; 104 } 105 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: { 106 Kind = EdgeKind_coff_x86_64::PCRel32; 107 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 108 Addend -= 1; 109 break; 110 } 111 default: { 112 return make_error<JITLinkError>("Unsupported x86_64 relocation:" + 113 formatv("{0:d}", Rel.getType())); 114 } 115 }; 116 117 Edge GE(Kind, Offset, *GraphSymbol, Addend); 118 LLVM_DEBUG({ 119 dbgs() << " "; 120 printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind)); 121 dbgs() << "\n"; 122 }); 123 124 BlockToFix.addEdge(std::move(GE)); 125 126 return Error::success(); 127 } 128 129 public: 130 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T) 131 : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {} 132 }; 133 134 class COFFLinkGraphLowering_x86_64 { 135 public: 136 // Lowers COFF x86_64 specific edges to generic x86_64 edges. 137 Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) { 138 for (auto *B : G.blocks()) { 139 for (auto &E : B->edges()) { 140 switch (E.getKind()) { 141 case EdgeKind_coff_x86_64::Pointer32NB: { 142 auto ImageBase = getImageBaseAddress(G, Ctx); 143 if (!ImageBase) 144 return ImageBase.takeError(); 145 E.setAddend(E.getAddend() - *ImageBase); 146 E.setKind(x86_64::Pointer32); 147 break; 148 } 149 case EdgeKind_coff_x86_64::PCRel32: { 150 E.setKind(x86_64::PCRel32); 151 break; 152 } 153 default: 154 break; 155 } 156 } 157 } 158 return Error::success(); 159 } 160 161 private: 162 static StringRef getImageBaseSymbolName() { return "__ImageBase"; } 163 Expected<JITTargetAddress> getImageBaseAddress(LinkGraph &G, 164 JITLinkContext &Ctx) { 165 if (this->ImageBase) 166 return this->ImageBase; 167 for (auto *S : G.defined_symbols()) 168 if (S->getName() == getImageBaseSymbolName()) { 169 this->ImageBase = S->getAddress().getValue(); 170 return this->ImageBase; 171 } 172 173 JITLinkContext::LookupMap Symbols; 174 Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol; 175 JITTargetAddress ImageBase; 176 Error Err = Error::success(); 177 Ctx.lookup(Symbols, 178 createLookupContinuation([&](Expected<AsyncLookupResult> LR) { 179 ErrorAsOutParameter EAO(&Err); 180 if (!LR) { 181 Err = LR.takeError(); 182 return; 183 } 184 auto &ImageBaseSymbol = LR->begin()->second; 185 ImageBase = ImageBaseSymbol.getAddress(); 186 })); 187 if (Err) 188 return std::move(Err); 189 this->ImageBase = ImageBase; 190 return ImageBase; 191 } 192 JITTargetAddress ImageBase = 0; 193 }; 194 195 Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) { 196 LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n"); 197 COFFLinkGraphLowering_x86_64 GraphLowering; 198 199 if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx)) 200 return Err; 201 202 return Error::success(); 203 } 204 } // namespace 205 206 namespace llvm { 207 namespace jitlink { 208 209 /// Return the string name of the given COFF x86_64 edge kind. 210 const char *getCOFFX86RelocationKindName(Edge::Kind R) { 211 switch (R) { 212 case PCRel32: 213 return "PCRel32"; 214 case Pointer32NB: 215 return "Pointer32NB"; 216 default: 217 return x86_64::getEdgeKindName(R); 218 } 219 } 220 221 Expected<std::unique_ptr<LinkGraph>> 222 createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) { 223 LLVM_DEBUG({ 224 dbgs() << "Building jitlink graph for new input " 225 << ObjectBuffer.getBufferIdentifier() << "...\n"; 226 }); 227 228 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer); 229 if (!COFFObj) 230 return COFFObj.takeError(); 231 232 return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple()) 233 .buildGraph(); 234 } 235 236 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G, 237 std::unique_ptr<JITLinkContext> Ctx) { 238 PassConfiguration Config; 239 const Triple &TT = G->getTargetTriple(); 240 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 241 // Add a mark-live pass. 242 if (auto MarkLive = Ctx->getMarkLivePass(TT)) { 243 Config.PrePrunePasses.push_back(std::move(MarkLive)); 244 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata")); 245 } else 246 Config.PrePrunePasses.push_back(markAllSymbolsLive); 247 248 // Add COFF edge lowering passes. 249 JITLinkContext *CtxPtr = Ctx.get(); 250 Config.PreFixupPasses.push_back( 251 [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); }); 252 } 253 254 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 255 return Ctx->notifyFailed(std::move(Err)); 256 257 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 258 } 259 260 } // namespace jitlink 261 } // namespace llvm 262