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().getSection()).getValue()); 225 E.setKind(x86_64::Pointer32); 226 break; 227 } 228 default: 229 break; 230 } 231 } 232 } 233 return Error::success(); 234 } 235 236 private: 237 orc::ExecutorAddr getSectionStart(Section &Sec) { 238 auto [It, Inserted] = SectionStartCache.try_emplace(&Sec); 239 if (Inserted) { 240 SectionRange Range(Sec); 241 It->second = Range.getStart(); 242 } 243 return It->second; 244 } 245 246 GetImageBaseSymbol GetImageBase; 247 DenseMap<Section *, orc::ExecutorAddr> SectionStartCache; 248 }; 249 } // namespace 250 251 namespace llvm { 252 namespace jitlink { 253 254 /// Return the string name of the given COFF x86_64 edge kind. 255 const char *getCOFFX86RelocationKindName(Edge::Kind R) { 256 switch (R) { 257 case PCRel32: 258 return "PCRel32"; 259 case Pointer32NB: 260 return "Pointer32NB"; 261 case Pointer64: 262 return "Pointer64"; 263 case SectionIdx16: 264 return "SectionIdx16"; 265 case SecRel32: 266 return "SecRel32"; 267 default: 268 return x86_64::getEdgeKindName(R); 269 } 270 } 271 272 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromCOFFObject_x86_64( 273 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { 274 LLVM_DEBUG({ 275 dbgs() << "Building jitlink graph for new input " 276 << ObjectBuffer.getBufferIdentifier() << "...\n"; 277 }); 278 279 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer); 280 if (!COFFObj) 281 return COFFObj.takeError(); 282 283 auto Features = (*COFFObj)->getFeatures(); 284 if (!Features) 285 return Features.takeError(); 286 287 return COFFLinkGraphBuilder_x86_64(**COFFObj, std::move(SSP), 288 (*COFFObj)->makeTriple(), 289 std::move(*Features)) 290 .buildGraph(); 291 } 292 293 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G, 294 std::unique_ptr<JITLinkContext> Ctx) { 295 PassConfiguration Config; 296 const Triple &TT = G->getTargetTriple(); 297 if (Ctx->shouldAddDefaultTargetPasses(TT)) { 298 // Add a mark-live pass. 299 if (auto MarkLive = Ctx->getMarkLivePass(TT)) { 300 Config.PrePrunePasses.push_back(std::move(MarkLive)); 301 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata")); 302 } else 303 Config.PrePrunePasses.push_back(markAllSymbolsLive); 304 305 // Add COFF edge lowering passes. 306 Config.PreFixupPasses.push_back(COFFLinkGraphLowering_x86_64()); 307 } 308 309 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 310 return Ctx->notifyFailed(std::move(Err)); 311 312 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 313 } 314 315 } // namespace jitlink 316 } // namespace llvm 317