317 lines · cpp
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-exception6//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 24using namespace llvm;25using namespace llvm::jitlink;26 27namespace {28 29enum EdgeKind_coff_x86_64 : Edge::Kind {30 PCRel32 = x86_64::FirstPlatformRelocation,31 Pointer32NB,32 Pointer64,33 SectionIdx16,34 SecRel32,35};36 37class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {38 friend class JITLinker<COFFJITLinker_x86_64>;39 40public: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 46private:47 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {48 return x86_64::applyFixup(G, B, E, nullptr);49 }50};51 52class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {53private: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 else153 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 handled163 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 187public: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 196class COFFLinkGraphLowering_x86_64 {197public: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 236private: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} // namespace250 251namespace llvm {252namespace jitlink {253 254/// Return the string name of the given COFF x86_64 edge kind.255const 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 272Expected<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 293void 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 } else303 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 jitlink316} // namespace llvm317