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 const SubtargetFeatures Features) 186 : COFFLinkGraphBuilder(Obj, std::move(T), std::move(Features), 187 getCOFFX86RelocationKindName) {} 188 }; 189 190 class COFFLinkGraphLowering_x86_64 { 191 public: 192 // Lowers COFF x86_64 specific edges to generic x86_64 edges. 193 Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) { 194 for (auto *B : G.blocks()) { 195 for (auto &E : B->edges()) { 196 switch (E.getKind()) { 197 case EdgeKind_coff_x86_64::Pointer32NB: { 198 auto ImageBase = getImageBaseAddress(G, Ctx); 199 if (!ImageBase) 200 return ImageBase.takeError(); 201 E.setAddend(E.getAddend() - ImageBase->getValue()); 202 E.setKind(x86_64::Pointer32); 203 break; 204 } 205 case EdgeKind_coff_x86_64::PCRel32: { 206 E.setKind(x86_64::PCRel32); 207 break; 208 } 209 case EdgeKind_coff_x86_64::Pointer64: { 210 E.setKind(x86_64::Pointer64); 211 break; 212 } 213 case EdgeKind_coff_x86_64::SectionIdx16: { 214 E.setKind(x86_64::Pointer16); 215 break; 216 } 217 case EdgeKind_coff_x86_64::SecRel32: { 218 E.setAddend(E.getAddend() - 219 getSectionStart(E.getTarget().getBlock().getSection()) 220 .getValue()); 221 E.setKind(x86_64::Pointer32); 222 break; 223 } 224 default: 225 break; 226 } 227 } 228 } 229 return Error::success(); 230 } 231 232 private: 233 static StringRef getImageBaseSymbolName() { return "__ImageBase"; } 234 235 orc::ExecutorAddr getSectionStart(Section &Sec) { 236 if (!SectionStartCache.count(&Sec)) { 237 SectionRange Range(Sec); 238 SectionStartCache[&Sec] = Range.getStart(); 239 } 240 return SectionStartCache[&Sec]; 241 } 242 243 Expected<orc::ExecutorAddr> getImageBaseAddress(LinkGraph &G, 244 JITLinkContext &Ctx) { 245 if (this->ImageBase) 246 return this->ImageBase; 247 for (auto *S : G.defined_symbols()) 248 if (S->getName() == getImageBaseSymbolName()) { 249 this->ImageBase = S->getAddress(); 250 return this->ImageBase; 251 } 252 253 JITLinkContext::LookupMap Symbols; 254 Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol; 255 orc::ExecutorAddr ImageBase; 256 Error Err = Error::success(); 257 Ctx.lookup(Symbols, 258 createLookupContinuation([&](Expected<AsyncLookupResult> LR) { 259 ErrorAsOutParameter EAO(&Err); 260 if (!LR) { 261 Err = LR.takeError(); 262 return; 263 } 264 ImageBase = LR->begin()->second.getAddress(); 265 })); 266 if (Err) 267 return std::move(Err); 268 this->ImageBase = ImageBase; 269 return ImageBase; 270 } 271 272 DenseMap<Section *, orc::ExecutorAddr> SectionStartCache; 273 orc::ExecutorAddr ImageBase; 274 }; 275 276 Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) { 277 LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n"); 278 COFFLinkGraphLowering_x86_64 GraphLowering; 279 280 if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx)) 281 return Err; 282 283 return Error::success(); 284 } 285 } // namespace 286 287 namespace llvm { 288 namespace jitlink { 289 290 /// Return the string name of the given COFF x86_64 edge kind. 291 const char *getCOFFX86RelocationKindName(Edge::Kind R) { 292 switch (R) { 293 case PCRel32: 294 return "PCRel32"; 295 case Pointer32NB: 296 return "Pointer32NB"; 297 case Pointer64: 298 return "Pointer64"; 299 case SectionIdx16: 300 return "SectionIdx16"; 301 case SecRel32: 302 return "SecRel32"; 303 default: 304 return x86_64::getEdgeKindName(R); 305 } 306 } 307 308 Expected<std::unique_ptr<LinkGraph>> 309 createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) { 310 LLVM_DEBUG({ 311 dbgs() << "Building jitlink graph for new input " 312 << ObjectBuffer.getBufferIdentifier() << "...\n"; 313 }); 314 315 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer); 316 if (!COFFObj) 317 return COFFObj.takeError(); 318 319 auto Features = (*COFFObj)->getFeatures(); 320 if (!Features) 321 return Features.takeError(); 322 323 return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple(), 324 std::move(*Features)) 325 .buildGraph(); 326 } 327 328 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G, 329 std::unique_ptr<JITLinkContext> Ctx) { 330 PassConfiguration Config; 331 const Triple &TT = G->getTargetTriple(); 332 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 333 // Add a mark-live pass. 334 if (auto MarkLive = Ctx->getMarkLivePass(TT)) { 335 Config.PrePrunePasses.push_back(std::move(MarkLive)); 336 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata")); 337 } else 338 Config.PrePrunePasses.push_back(markAllSymbolsLive); 339 340 // Add COFF edge lowering passes. 341 JITLinkContext *CtxPtr = Ctx.get(); 342 Config.PreFixupPasses.push_back( 343 [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); }); 344 } 345 346 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 347 return Ctx->notifyFailed(std::move(Err)); 348 349 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 350 } 351 352 } // namespace jitlink 353 } // namespace llvm 354