ExecutorAddr was introduced in b8e5f91816 as an eventual replacement for
JITTargetAddress. ExecutorSymbolDef is introduced in this patch as a
replacement for JITEvaluatedSymbol: ExecutorSymbolDef is an (ExecutorAddr,
JITSymbolFlags) pair, where JITEvaluatedSymbol was a (JITTargetAddress,
JITSymbolFlags) pair.
A number of APIs had already migrated from JITTargetAddress to ExecutorAddr,
but many of ORC's internals were still using the older type. This patch aims
to address that.
Some public APIs are affected as well. If you need to migrate your APIs you can
use the following operations:
* ExecutorAddr::toPtr replaces jitTargetAddressToPointer and
jitTargetAddressToFunction.
* ExecutorAddr::fromPtr replace pointerToJITTargetAddress.
* ExecutorAddr(JITTargetAddress) creates an ExecutorAddr value from a
JITTargetAddress.
* ExecutorAddr::getValue() creates a JITTargetAddress value from an
ExecutorAddr.
JITTargetAddress and JITEvaluatedSymbol will remain in JITSymbol.h for now, but
the aim will be to eventually deprecate and remove these types (probably when
MCJIT and RuntimeDyld are deprecated).
347 lines
11 KiB
C++
347 lines
11 KiB
C++
//===----- 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->getValue());
|
|
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<orc::ExecutorAddr> 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();
|
|
return this->ImageBase;
|
|
}
|
|
|
|
JITLinkContext::LookupMap Symbols;
|
|
Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
|
|
orc::ExecutorAddr ImageBase;
|
|
Error Err = Error::success();
|
|
Ctx.lookup(Symbols,
|
|
createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
|
|
ErrorAsOutParameter EAO(&Err);
|
|
if (!LR) {
|
|
Err = LR.takeError();
|
|
return;
|
|
}
|
|
ImageBase = LR->begin()->second.getAddress();
|
|
}));
|
|
if (Err)
|
|
return std::move(Err);
|
|
this->ImageBase = ImageBase;
|
|
return ImageBase;
|
|
}
|
|
|
|
DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
|
|
orc::ExecutorAddr ImageBase;
|
|
};
|
|
|
|
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
|