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 Pointer64, 33 SectionIdx16, 34 SecRel32, 35 }; 36 37 class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> { 38 friend class JITLinker<COFFJITLinker_x86_64>; 39 40 public: 41 COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 42 std::unique_ptr<LinkGraph> G, 43 PassConfiguration PassConfig) 44 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 45 46 private: 47 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 48 return x86_64::applyFixup(G, B, E, nullptr); 49 } 50 }; 51 52 class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder { 53 private: 54 Error addRelocations() override { 55 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 56 57 for (const auto &RelSect : sections()) 58 if (Error Err = COFFLinkGraphBuilder::forEachRelocation( 59 RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation)) 60 return Err; 61 62 return Error::success(); 63 } 64 65 Error addSingleRelocation(const object::RelocationRef &Rel, 66 const object::SectionRef &FixupSect, 67 Block &BlockToFix) { 68 const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel); 69 auto SymbolIt = Rel.getSymbol(); 70 if (SymbolIt == getObject().symbol_end()) { 71 return make_error<StringError>( 72 formatv("Invalid symbol index in relocation entry. " 73 "index: {0}, section: {1}", 74 COFFRel->SymbolTableIndex, FixupSect.getIndex()), 75 inconvertibleErrorCode()); 76 } 77 78 object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt); 79 COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol); 80 81 Symbol *GraphSymbol = getGraphSymbol(SymIndex); 82 if (!GraphSymbol) 83 return make_error<StringError>( 84 formatv("Could not find symbol at given index, did you add it to " 85 "JITSymbolTable? index: {0}, section: {1}", 86 SymIndex, FixupSect.getIndex()), 87 inconvertibleErrorCode()); 88 89 int64_t Addend = 0; 90 orc::ExecutorAddr FixupAddress = 91 orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset(); 92 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 93 94 Edge::Kind Kind = Edge::Invalid; 95 const char *FixupPtr = BlockToFix.getContent().data() + Offset; 96 97 switch (Rel.getType()) { 98 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: { 99 Kind = EdgeKind_coff_x86_64::Pointer32NB; 100 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 101 break; 102 } 103 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: { 104 Kind = EdgeKind_coff_x86_64::PCRel32; 105 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 106 break; 107 } 108 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: { 109 Kind = EdgeKind_coff_x86_64::PCRel32; 110 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 111 Addend -= 1; 112 break; 113 } 114 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: { 115 Kind = EdgeKind_coff_x86_64::PCRel32; 116 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 117 Addend -= 2; 118 break; 119 } 120 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: { 121 Kind = EdgeKind_coff_x86_64::PCRel32; 122 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 123 Addend -= 3; 124 break; 125 } 126 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: { 127 Kind = EdgeKind_coff_x86_64::PCRel32; 128 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 129 Addend -= 4; 130 break; 131 } 132 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: { 133 Kind = EdgeKind_coff_x86_64::PCRel32; 134 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 135 Addend -= 5; 136 break; 137 } 138 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: { 139 Kind = EdgeKind_coff_x86_64::Pointer64; 140 Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr); 141 break; 142 } 143 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: { 144 Kind = EdgeKind_coff_x86_64::SectionIdx16; 145 Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr); 146 uint64_t SectionIdx = 0; 147 if (COFFSymbol.isAbsolute()) 148 SectionIdx = getObject().getNumberOfSections() + 1; 149 else 150 SectionIdx = COFFSymbol.getSectionNumber(); 151 auto *AbsSym = &getGraph().addAbsoluteSymbol( 152 "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong, 153 Scope::Local, false); 154 GraphSymbol = AbsSym; 155 break; 156 } 157 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: { 158 // FIXME: SECREL to external symbol should be handled 159 if (!GraphSymbol->isDefined()) 160 return Error::success(); 161 Kind = EdgeKind_coff_x86_64::SecRel32; 162 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 163 break; 164 } 165 default: { 166 return make_error<JITLinkError>("Unsupported x86_64 relocation:" + 167 formatv("{0:d}", Rel.getType())); 168 } 169 }; 170 171 Edge GE(Kind, Offset, *GraphSymbol, Addend); 172 LLVM_DEBUG({ 173 dbgs() << " "; 174 printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind)); 175 dbgs() << "\n"; 176 }); 177 178 BlockToFix.addEdge(std::move(GE)); 179 180 return Error::success(); 181 } 182 183 public: 184 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T) 185 : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {} 186 }; 187 188 class COFFLinkGraphLowering_x86_64 { 189 public: 190 // Lowers COFF x86_64 specific edges to generic x86_64 edges. 191 Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) { 192 for (auto *B : G.blocks()) { 193 for (auto &E : B->edges()) { 194 switch (E.getKind()) { 195 case EdgeKind_coff_x86_64::Pointer32NB: { 196 auto ImageBase = getImageBaseAddress(G, Ctx); 197 if (!ImageBase) 198 return ImageBase.takeError(); 199 E.setAddend(E.getAddend() - *ImageBase); 200 E.setKind(x86_64::Pointer32); 201 break; 202 } 203 case EdgeKind_coff_x86_64::PCRel32: { 204 E.setKind(x86_64::PCRel32); 205 break; 206 } 207 case EdgeKind_coff_x86_64::Pointer64: { 208 E.setKind(x86_64::Pointer64); 209 break; 210 } 211 case EdgeKind_coff_x86_64::SectionIdx16: { 212 E.setKind(x86_64::Pointer16); 213 break; 214 } 215 case EdgeKind_coff_x86_64::SecRel32: { 216 E.setAddend(E.getAddend() - 217 getSectionStart(E.getTarget().getBlock().getSection()) 218 .getValue()); 219 E.setKind(x86_64::Pointer32); 220 break; 221 } 222 default: 223 break; 224 } 225 } 226 } 227 return Error::success(); 228 } 229 230 private: 231 static StringRef getImageBaseSymbolName() { return "__ImageBase"; } 232 233 orc::ExecutorAddr getSectionStart(Section &Sec) { 234 if (!SectionStartCache.count(&Sec)) { 235 SectionRange Range(Sec); 236 SectionStartCache[&Sec] = Range.getStart(); 237 } 238 return SectionStartCache[&Sec]; 239 } 240 241 Expected<JITTargetAddress> getImageBaseAddress(LinkGraph &G, 242 JITLinkContext &Ctx) { 243 if (this->ImageBase) 244 return this->ImageBase; 245 for (auto *S : G.defined_symbols()) 246 if (S->getName() == getImageBaseSymbolName()) { 247 this->ImageBase = S->getAddress().getValue(); 248 return this->ImageBase; 249 } 250 251 JITLinkContext::LookupMap Symbols; 252 Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol; 253 JITTargetAddress ImageBase; 254 Error Err = Error::success(); 255 Ctx.lookup(Symbols, 256 createLookupContinuation([&](Expected<AsyncLookupResult> LR) { 257 ErrorAsOutParameter EAO(&Err); 258 if (!LR) { 259 Err = LR.takeError(); 260 return; 261 } 262 auto &ImageBaseSymbol = LR->begin()->second; 263 ImageBase = ImageBaseSymbol.getAddress(); 264 })); 265 if (Err) 266 return std::move(Err); 267 this->ImageBase = ImageBase; 268 return ImageBase; 269 } 270 271 DenseMap<Section *, orc::ExecutorAddr> SectionStartCache; 272 JITTargetAddress ImageBase = 0; 273 }; 274 275 Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) { 276 LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n"); 277 COFFLinkGraphLowering_x86_64 GraphLowering; 278 279 if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx)) 280 return Err; 281 282 return Error::success(); 283 } 284 } // namespace 285 286 namespace llvm { 287 namespace jitlink { 288 289 /// Return the string name of the given COFF x86_64 edge kind. 290 const char *getCOFFX86RelocationKindName(Edge::Kind R) { 291 switch (R) { 292 case PCRel32: 293 return "PCRel32"; 294 case Pointer32NB: 295 return "Pointer32NB"; 296 case Pointer64: 297 return "Pointer64"; 298 case SectionIdx16: 299 return "SectionIdx16"; 300 case SecRel32: 301 return "SecRel32"; 302 default: 303 return x86_64::getEdgeKindName(R); 304 } 305 } 306 307 Expected<std::unique_ptr<LinkGraph>> 308 createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) { 309 LLVM_DEBUG({ 310 dbgs() << "Building jitlink graph for new input " 311 << ObjectBuffer.getBufferIdentifier() << "...\n"; 312 }); 313 314 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer); 315 if (!COFFObj) 316 return COFFObj.takeError(); 317 318 return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple()) 319 .buildGraph(); 320 } 321 322 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G, 323 std::unique_ptr<JITLinkContext> Ctx) { 324 PassConfiguration Config; 325 const Triple &TT = G->getTargetTriple(); 326 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 327 // Add a mark-live pass. 328 if (auto MarkLive = Ctx->getMarkLivePass(TT)) { 329 Config.PrePrunePasses.push_back(std::move(MarkLive)); 330 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata")); 331 } else 332 Config.PrePrunePasses.push_back(markAllSymbolsLive); 333 334 // Add COFF edge lowering passes. 335 JITLinkContext *CtxPtr = Ctx.get(); 336 Config.PreFixupPasses.push_back( 337 [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); }); 338 } 339 340 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 341 return Ctx->notifyFailed(std::move(Err)); 342 343 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 344 } 345 346 } // namespace jitlink 347 } // namespace llvm 348