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 Symbol *ImageBase = GetImageBaseSymbol()(getGraph()); 97 98 switch (Rel.getType()) { 99 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: { 100 if (!ImageBase) 101 ImageBase = &addImageBaseSymbol(); 102 Kind = EdgeKind_coff_x86_64::Pointer32NB; 103 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 104 break; 105 } 106 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: { 107 Kind = EdgeKind_coff_x86_64::PCRel32; 108 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 109 break; 110 } 111 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: { 112 Kind = EdgeKind_coff_x86_64::PCRel32; 113 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 114 Addend -= 1; 115 break; 116 } 117 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: { 118 Kind = EdgeKind_coff_x86_64::PCRel32; 119 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 120 Addend -= 2; 121 break; 122 } 123 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: { 124 Kind = EdgeKind_coff_x86_64::PCRel32; 125 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 126 Addend -= 3; 127 break; 128 } 129 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: { 130 Kind = EdgeKind_coff_x86_64::PCRel32; 131 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 132 Addend -= 4; 133 break; 134 } 135 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: { 136 Kind = EdgeKind_coff_x86_64::PCRel32; 137 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 138 Addend -= 5; 139 break; 140 } 141 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: { 142 Kind = EdgeKind_coff_x86_64::Pointer64; 143 Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr); 144 break; 145 } 146 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: { 147 Kind = EdgeKind_coff_x86_64::SectionIdx16; 148 Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr); 149 uint64_t SectionIdx = 0; 150 if (COFFSymbol.isAbsolute()) 151 SectionIdx = getObject().getNumberOfSections() + 1; 152 else 153 SectionIdx = COFFSymbol.getSectionNumber(); 154 155 auto *AbsSym = &getGraph().addAbsoluteSymbol( 156 "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong, 157 Scope::Local, false); 158 GraphSymbol = AbsSym; 159 break; 160 } 161 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: { 162 // FIXME: SECREL to external symbol should be handled 163 if (!GraphSymbol->isDefined()) 164 return Error::success(); 165 Kind = EdgeKind_coff_x86_64::SecRel32; 166 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr); 167 break; 168 } 169 default: { 170 return make_error<JITLinkError>("Unsupported x86_64 relocation:" + 171 formatv("{0:d}", Rel.getType())); 172 } 173 }; 174 175 Edge GE(Kind, Offset, *GraphSymbol, Addend); 176 LLVM_DEBUG({ 177 dbgs() << " "; 178 printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind)); 179 dbgs() << "\n"; 180 }); 181 182 BlockToFix.addEdge(std::move(GE)); 183 184 return Error::success(); 185 } 186 187 public: 188 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, 189 std::shared_ptr<orc::SymbolStringPool> SSP, 190 const Triple T, const SubtargetFeatures Features) 191 : COFFLinkGraphBuilder(Obj, std::move(SSP), std::move(T), 192 std::move(Features), 193 getCOFFX86RelocationKindName) {} 194 }; 195 196 class COFFLinkGraphLowering_x86_64 { 197 public: 198 // Lowers COFF x86_64 specific edges to generic x86_64 edges. 199 Error operator()(LinkGraph &G) { 200 for (auto *B : G.blocks()) { 201 for (auto &E : B->edges()) { 202 switch (E.getKind()) { 203 case EdgeKind_coff_x86_64::Pointer32NB: { 204 auto ImageBase = GetImageBase(G); 205 assert(ImageBase && "__ImageBase symbol must be defined"); 206 E.setAddend(E.getAddend() - ImageBase->getAddress().getValue()); 207 E.setKind(x86_64::Pointer32); 208 break; 209 } 210 case EdgeKind_coff_x86_64::PCRel32: { 211 E.setKind(x86_64::PCRel32); 212 break; 213 } 214 case EdgeKind_coff_x86_64::Pointer64: { 215 E.setKind(x86_64::Pointer64); 216 break; 217 } 218 case EdgeKind_coff_x86_64::SectionIdx16: { 219 E.setKind(x86_64::Pointer16); 220 break; 221 } 222 case EdgeKind_coff_x86_64::SecRel32: { 223 E.setAddend(E.getAddend() - 224 getSectionStart(E.getTarget().getBlock().getSection()) 225 .getValue()); 226 E.setKind(x86_64::Pointer32); 227 break; 228 } 229 default: 230 break; 231 } 232 } 233 } 234 return Error::success(); 235 } 236 237 private: 238 orc::ExecutorAddr getSectionStart(Section &Sec) { 239 if (!SectionStartCache.count(&Sec)) { 240 SectionRange Range(Sec); 241 SectionStartCache[&Sec] = Range.getStart(); 242 return Range.getStart(); 243 } 244 return SectionStartCache[&Sec]; 245 } 246 247 GetImageBaseSymbol GetImageBase; 248 DenseMap<Section *, orc::ExecutorAddr> SectionStartCache; 249 }; 250 } // namespace 251 252 namespace llvm { 253 namespace jitlink { 254 255 /// Return the string name of the given COFF x86_64 edge kind. 256 const char *getCOFFX86RelocationKindName(Edge::Kind R) { 257 switch (R) { 258 case PCRel32: 259 return "PCRel32"; 260 case Pointer32NB: 261 return "Pointer32NB"; 262 case Pointer64: 263 return "Pointer64"; 264 case SectionIdx16: 265 return "SectionIdx16"; 266 case SecRel32: 267 return "SecRel32"; 268 default: 269 return x86_64::getEdgeKindName(R); 270 } 271 } 272 273 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromCOFFObject_x86_64( 274 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { 275 LLVM_DEBUG({ 276 dbgs() << "Building jitlink graph for new input " 277 << ObjectBuffer.getBufferIdentifier() << "...\n"; 278 }); 279 280 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer); 281 if (!COFFObj) 282 return COFFObj.takeError(); 283 284 auto Features = (*COFFObj)->getFeatures(); 285 if (!Features) 286 return Features.takeError(); 287 288 return COFFLinkGraphBuilder_x86_64(**COFFObj, std::move(SSP), 289 (*COFFObj)->makeTriple(), 290 std::move(*Features)) 291 .buildGraph(); 292 } 293 294 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G, 295 std::unique_ptr<JITLinkContext> Ctx) { 296 PassConfiguration Config; 297 const Triple &TT = G->getTargetTriple(); 298 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 299 // Add a mark-live pass. 300 if (auto MarkLive = Ctx->getMarkLivePass(TT)) { 301 Config.PrePrunePasses.push_back(std::move(MarkLive)); 302 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata")); 303 } else 304 Config.PrePrunePasses.push_back(markAllSymbolsLive); 305 306 // Add COFF edge lowering passes. 307 Config.PreFixupPasses.push_back(COFFLinkGraphLowering_x86_64()); 308 } 309 310 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 311 return Ctx->notifyFailed(std::move(Err)); 312 313 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 314 } 315 316 } // namespace jitlink 317 } // namespace llvm 318