123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- //===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // COFF/x86_64 jit-link implementation.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"
- #include "COFFLinkGraphBuilder.h"
- #include "JITLinkGeneric.h"
- #include "SEHFrameSupport.h"
- #include "llvm/BinaryFormat/COFF.h"
- #include "llvm/ExecutionEngine/JITLink/x86_64.h"
- #include "llvm/Object/COFF.h"
- #include "llvm/Support/Endian.h"
- #define DEBUG_TYPE "jitlink"
- using namespace llvm;
- using namespace llvm::jitlink;
- namespace {
- enum EdgeKind_coff_x86_64 : Edge::Kind {
- PCRel32 = x86_64::FirstPlatformRelocation,
- Pointer32NB,
- Pointer64,
- SectionIdx16,
- SecRel32,
- };
- class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
- friend class JITLinker<COFFJITLinker_x86_64>;
- public:
- COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
- std::unique_ptr<LinkGraph> G,
- PassConfiguration PassConfig)
- : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
- private:
- Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
- return x86_64::applyFixup(G, B, E, nullptr);
- }
- };
- class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
- private:
- Error addRelocations() override {
- LLVM_DEBUG(dbgs() << "Processing relocations:\n");
- for (const auto &RelSect : sections())
- if (Error Err = COFFLinkGraphBuilder::forEachRelocation(
- RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
- return Err;
- return Error::success();
- }
- Error addSingleRelocation(const object::RelocationRef &Rel,
- const object::SectionRef &FixupSect,
- Block &BlockToFix) {
- const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
- auto SymbolIt = Rel.getSymbol();
- if (SymbolIt == getObject().symbol_end()) {
- return make_error<StringError>(
- formatv("Invalid symbol index in relocation entry. "
- "index: {0}, section: {1}",
- COFFRel->SymbolTableIndex, FixupSect.getIndex()),
- inconvertibleErrorCode());
- }
- object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
- COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
- Symbol *GraphSymbol = getGraphSymbol(SymIndex);
- if (!GraphSymbol)
- return make_error<StringError>(
- formatv("Could not find symbol at given index, did you add it to "
- "JITSymbolTable? index: {0}, section: {1}",
- SymIndex, FixupSect.getIndex()),
- inconvertibleErrorCode());
- int64_t Addend = 0;
- orc::ExecutorAddr FixupAddress =
- orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
- Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
- Edge::Kind Kind = Edge::Invalid;
- const char *FixupPtr = BlockToFix.getContent().data() + Offset;
- switch (Rel.getType()) {
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
- Kind = EdgeKind_coff_x86_64::Pointer32NB;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
- Kind = EdgeKind_coff_x86_64::PCRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
- Kind = EdgeKind_coff_x86_64::PCRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- Addend -= 1;
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: {
- Kind = EdgeKind_coff_x86_64::PCRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- Addend -= 2;
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: {
- Kind = EdgeKind_coff_x86_64::PCRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- Addend -= 3;
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: {
- Kind = EdgeKind_coff_x86_64::PCRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- Addend -= 4;
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: {
- Kind = EdgeKind_coff_x86_64::PCRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- Addend -= 5;
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: {
- Kind = EdgeKind_coff_x86_64::Pointer64;
- Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: {
- Kind = EdgeKind_coff_x86_64::SectionIdx16;
- Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);
- uint64_t SectionIdx = 0;
- if (COFFSymbol.isAbsolute())
- SectionIdx = getObject().getNumberOfSections() + 1;
- else
- SectionIdx = COFFSymbol.getSectionNumber();
- auto *AbsSym = &getGraph().addAbsoluteSymbol(
- "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,
- Scope::Local, false);
- GraphSymbol = AbsSym;
- break;
- }
- case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: {
- // FIXME: SECREL to external symbol should be handled
- if (!GraphSymbol->isDefined())
- return Error::success();
- Kind = EdgeKind_coff_x86_64::SecRel32;
- Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
- break;
- }
- default: {
- return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
- formatv("{0:d}", Rel.getType()));
- }
- };
- Edge GE(Kind, Offset, *GraphSymbol, Addend);
- LLVM_DEBUG({
- dbgs() << " ";
- printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
- dbgs() << "\n";
- });
- BlockToFix.addEdge(std::move(GE));
- return Error::success();
- }
- public:
- COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T)
- : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {}
- };
- class COFFLinkGraphLowering_x86_64 {
- public:
- // Lowers COFF x86_64 specific edges to generic x86_64 edges.
- Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {
- for (auto *B : G.blocks()) {
- for (auto &E : B->edges()) {
- switch (E.getKind()) {
- case EdgeKind_coff_x86_64::Pointer32NB: {
- auto ImageBase = getImageBaseAddress(G, Ctx);
- if (!ImageBase)
- return ImageBase.takeError();
- E.setAddend(E.getAddend() - *ImageBase);
- E.setKind(x86_64::Pointer32);
- break;
- }
- case EdgeKind_coff_x86_64::PCRel32: {
- E.setKind(x86_64::PCRel32);
- break;
- }
- case EdgeKind_coff_x86_64::Pointer64: {
- E.setKind(x86_64::Pointer64);
- break;
- }
- case EdgeKind_coff_x86_64::SectionIdx16: {
- E.setKind(x86_64::Pointer16);
- break;
- }
- case EdgeKind_coff_x86_64::SecRel32: {
- E.setAddend(E.getAddend() -
- getSectionStart(E.getTarget().getBlock().getSection())
- .getValue());
- E.setKind(x86_64::Pointer32);
- break;
- }
- default:
- break;
- }
- }
- }
- return Error::success();
- }
- private:
- static StringRef getImageBaseSymbolName() { return "__ImageBase"; }
- orc::ExecutorAddr getSectionStart(Section &Sec) {
- if (!SectionStartCache.count(&Sec)) {
- SectionRange Range(Sec);
- SectionStartCache[&Sec] = Range.getStart();
- }
- return SectionStartCache[&Sec];
- }
- Expected<JITTargetAddress> getImageBaseAddress(LinkGraph &G,
- JITLinkContext &Ctx) {
- if (this->ImageBase)
- return this->ImageBase;
- for (auto *S : G.defined_symbols())
- if (S->getName() == getImageBaseSymbolName()) {
- this->ImageBase = S->getAddress().getValue();
- return this->ImageBase;
- }
- JITLinkContext::LookupMap Symbols;
- Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
- JITTargetAddress ImageBase;
- Error Err = Error::success();
- Ctx.lookup(Symbols,
- createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
- ErrorAsOutParameter EAO(&Err);
- if (!LR) {
- Err = LR.takeError();
- return;
- }
- auto &ImageBaseSymbol = LR->begin()->second;
- ImageBase = ImageBaseSymbol.getAddress();
- }));
- if (Err)
- return std::move(Err);
- this->ImageBase = ImageBase;
- return ImageBase;
- }
- DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
- JITTargetAddress ImageBase = 0;
- };
- Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {
- LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
- COFFLinkGraphLowering_x86_64 GraphLowering;
- if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))
- return Err;
- return Error::success();
- }
- } // namespace
- namespace llvm {
- namespace jitlink {
- /// Return the string name of the given COFF x86_64 edge kind.
- const char *getCOFFX86RelocationKindName(Edge::Kind R) {
- switch (R) {
- case PCRel32:
- return "PCRel32";
- case Pointer32NB:
- return "Pointer32NB";
- case Pointer64:
- return "Pointer64";
- case SectionIdx16:
- return "SectionIdx16";
- case SecRel32:
- return "SecRel32";
- default:
- return x86_64::getEdgeKindName(R);
- }
- }
- Expected<std::unique_ptr<LinkGraph>>
- createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) {
- LLVM_DEBUG({
- dbgs() << "Building jitlink graph for new input "
- << ObjectBuffer.getBufferIdentifier() << "...\n";
- });
- auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);
- if (!COFFObj)
- return COFFObj.takeError();
- return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple())
- .buildGraph();
- }
- void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
- std::unique_ptr<JITLinkContext> Ctx) {
- PassConfiguration Config;
- const Triple &TT = G->getTargetTriple();
- if (Ctx->shouldAddDefaultTargetPasses(TT)) {
- // Add a mark-live pass.
- if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
- Config.PrePrunePasses.push_back(std::move(MarkLive));
- Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
- } else
- Config.PrePrunePasses.push_back(markAllSymbolsLive);
- // Add COFF edge lowering passes.
- JITLinkContext *CtxPtr = Ctx.get();
- Config.PreFixupPasses.push_back(
- [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });
- }
- if (auto Err = Ctx->modifyPassConfig(*G, Config))
- return Ctx->notifyFailed(std::move(Err));
- COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
- }
- } // namespace jitlink
- } // namespace llvm
|