Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp
35271 views
//===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// COFF/x86_64 jit-link implementation.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"13#include "COFFLinkGraphBuilder.h"14#include "JITLinkGeneric.h"15#include "SEHFrameSupport.h"16#include "llvm/BinaryFormat/COFF.h"17#include "llvm/ExecutionEngine/JITLink/x86_64.h"18#include "llvm/Object/COFF.h"19#include "llvm/Support/Endian.h"2021#define DEBUG_TYPE "jitlink"2223using namespace llvm;24using namespace llvm::jitlink;2526namespace {2728enum EdgeKind_coff_x86_64 : Edge::Kind {29PCRel32 = x86_64::FirstPlatformRelocation,30Pointer32NB,31Pointer64,32SectionIdx16,33SecRel32,34};3536class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {37friend class JITLinker<COFFJITLinker_x86_64>;3839public:40COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,41std::unique_ptr<LinkGraph> G,42PassConfiguration PassConfig)43: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}4445private:46Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {47return x86_64::applyFixup(G, B, E, nullptr);48}49};5051class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {52private:53Error addRelocations() override {54LLVM_DEBUG(dbgs() << "Processing relocations:\n");5556for (const auto &RelSect : sections())57if (Error Err = COFFLinkGraphBuilder::forEachRelocation(58RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))59return Err;6061return Error::success();62}6364Error addSingleRelocation(const object::RelocationRef &Rel,65const object::SectionRef &FixupSect,66Block &BlockToFix) {67const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);68auto SymbolIt = Rel.getSymbol();69if (SymbolIt == getObject().symbol_end()) {70return make_error<StringError>(71formatv("Invalid symbol index in relocation entry. "72"index: {0}, section: {1}",73COFFRel->SymbolTableIndex, FixupSect.getIndex()),74inconvertibleErrorCode());75}7677object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);78COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);7980Symbol *GraphSymbol = getGraphSymbol(SymIndex);81if (!GraphSymbol)82return make_error<StringError>(83formatv("Could not find symbol at given index, did you add it to "84"JITSymbolTable? index: {0}, section: {1}",85SymIndex, FixupSect.getIndex()),86inconvertibleErrorCode());8788int64_t Addend = 0;89orc::ExecutorAddr FixupAddress =90orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();91Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();9293Edge::Kind Kind = Edge::Invalid;94const char *FixupPtr = BlockToFix.getContent().data() + Offset;9596switch (Rel.getType()) {97case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {98Kind = EdgeKind_coff_x86_64::Pointer32NB;99Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);100break;101}102case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {103Kind = EdgeKind_coff_x86_64::PCRel32;104Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);105break;106}107case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {108Kind = EdgeKind_coff_x86_64::PCRel32;109Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);110Addend -= 1;111break;112}113case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: {114Kind = EdgeKind_coff_x86_64::PCRel32;115Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);116Addend -= 2;117break;118}119case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: {120Kind = EdgeKind_coff_x86_64::PCRel32;121Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);122Addend -= 3;123break;124}125case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: {126Kind = EdgeKind_coff_x86_64::PCRel32;127Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);128Addend -= 4;129break;130}131case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: {132Kind = EdgeKind_coff_x86_64::PCRel32;133Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);134Addend -= 5;135break;136}137case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: {138Kind = EdgeKind_coff_x86_64::Pointer64;139Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);140break;141}142case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: {143Kind = EdgeKind_coff_x86_64::SectionIdx16;144Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);145uint64_t SectionIdx = 0;146if (COFFSymbol.isAbsolute())147SectionIdx = getObject().getNumberOfSections() + 1;148else149SectionIdx = COFFSymbol.getSectionNumber();150auto *AbsSym = &getGraph().addAbsoluteSymbol(151"secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,152Scope::Local, false);153GraphSymbol = AbsSym;154break;155}156case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: {157// FIXME: SECREL to external symbol should be handled158if (!GraphSymbol->isDefined())159return Error::success();160Kind = EdgeKind_coff_x86_64::SecRel32;161Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);162break;163}164default: {165return make_error<JITLinkError>("Unsupported x86_64 relocation:" +166formatv("{0:d}", Rel.getType()));167}168};169170Edge GE(Kind, Offset, *GraphSymbol, Addend);171LLVM_DEBUG({172dbgs() << " ";173printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));174dbgs() << "\n";175});176177BlockToFix.addEdge(std::move(GE));178179return Error::success();180}181182public:183COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T,184const SubtargetFeatures Features)185: COFFLinkGraphBuilder(Obj, std::move(T), std::move(Features),186getCOFFX86RelocationKindName) {}187};188189class COFFLinkGraphLowering_x86_64 {190public:191// Lowers COFF x86_64 specific edges to generic x86_64 edges.192Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {193for (auto *B : G.blocks()) {194for (auto &E : B->edges()) {195switch (E.getKind()) {196case EdgeKind_coff_x86_64::Pointer32NB: {197auto ImageBase = getImageBaseAddress(G, Ctx);198if (!ImageBase)199return ImageBase.takeError();200E.setAddend(E.getAddend() - ImageBase->getValue());201E.setKind(x86_64::Pointer32);202break;203}204case EdgeKind_coff_x86_64::PCRel32: {205E.setKind(x86_64::PCRel32);206break;207}208case EdgeKind_coff_x86_64::Pointer64: {209E.setKind(x86_64::Pointer64);210break;211}212case EdgeKind_coff_x86_64::SectionIdx16: {213E.setKind(x86_64::Pointer16);214break;215}216case EdgeKind_coff_x86_64::SecRel32: {217E.setAddend(E.getAddend() -218getSectionStart(E.getTarget().getBlock().getSection())219.getValue());220E.setKind(x86_64::Pointer32);221break;222}223default:224break;225}226}227}228return Error::success();229}230231private:232static StringRef getImageBaseSymbolName() { return "__ImageBase"; }233234orc::ExecutorAddr getSectionStart(Section &Sec) {235if (!SectionStartCache.count(&Sec)) {236SectionRange Range(Sec);237SectionStartCache[&Sec] = Range.getStart();238}239return SectionStartCache[&Sec];240}241242Expected<orc::ExecutorAddr> getImageBaseAddress(LinkGraph &G,243JITLinkContext &Ctx) {244if (this->ImageBase)245return this->ImageBase;246for (auto *S : G.defined_symbols())247if (S->getName() == getImageBaseSymbolName()) {248this->ImageBase = S->getAddress();249return this->ImageBase;250}251252JITLinkContext::LookupMap Symbols;253Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;254orc::ExecutorAddr ImageBase;255Error Err = Error::success();256Ctx.lookup(Symbols,257createLookupContinuation([&](Expected<AsyncLookupResult> LR) {258ErrorAsOutParameter EAO(&Err);259if (!LR) {260Err = LR.takeError();261return;262}263ImageBase = LR->begin()->second.getAddress();264}));265if (Err)266return std::move(Err);267this->ImageBase = ImageBase;268return ImageBase;269}270271DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;272orc::ExecutorAddr ImageBase;273};274275Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {276LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");277COFFLinkGraphLowering_x86_64 GraphLowering;278279if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))280return Err;281282return Error::success();283}284} // namespace285286namespace llvm {287namespace jitlink {288289/// Return the string name of the given COFF x86_64 edge kind.290const char *getCOFFX86RelocationKindName(Edge::Kind R) {291switch (R) {292case PCRel32:293return "PCRel32";294case Pointer32NB:295return "Pointer32NB";296case Pointer64:297return "Pointer64";298case SectionIdx16:299return "SectionIdx16";300case SecRel32:301return "SecRel32";302default:303return x86_64::getEdgeKindName(R);304}305}306307Expected<std::unique_ptr<LinkGraph>>308createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) {309LLVM_DEBUG({310dbgs() << "Building jitlink graph for new input "311<< ObjectBuffer.getBufferIdentifier() << "...\n";312});313314auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);315if (!COFFObj)316return COFFObj.takeError();317318auto Features = (*COFFObj)->getFeatures();319if (!Features)320return Features.takeError();321322return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple(),323std::move(*Features))324.buildGraph();325}326327void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,328std::unique_ptr<JITLinkContext> Ctx) {329PassConfiguration Config;330const Triple &TT = G->getTargetTriple();331if (Ctx->shouldAddDefaultTargetPasses(TT)) {332// Add a mark-live pass.333if (auto MarkLive = Ctx->getMarkLivePass(TT)) {334Config.PrePrunePasses.push_back(std::move(MarkLive));335Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));336} else337Config.PrePrunePasses.push_back(markAllSymbolsLive);338339// Add COFF edge lowering passes.340JITLinkContext *CtxPtr = Ctx.get();341Config.PreFixupPasses.push_back(342[CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });343}344345if (auto Err = Ctx->modifyPassConfig(*G, Config))346return Ctx->notifyFailed(std::move(Err));347348COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));349}350351} // namespace jitlink352} // namespace llvm353354355