forked from OSchip/llvm-project
262 lines
8.0 KiB
C++
262 lines
8.0 KiB
C++
//===------------- JITLink.cpp - Core Run-time JIT linker APIs ------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
|
|
|
#include "llvm/BinaryFormat/Magic.h"
|
|
#include "llvm/ExecutionEngine/JITLink/MachO.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/Process.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::object;
|
|
|
|
#define DEBUG_TYPE "jitlink"
|
|
|
|
namespace {
|
|
|
|
enum JITLinkErrorCode { GenericJITLinkError = 1 };
|
|
|
|
// FIXME: This class is only here to support the transition to llvm::Error. It
|
|
// will be removed once this transition is complete. Clients should prefer to
|
|
// deal with the Error value directly, rather than converting to error_code.
|
|
class JITLinkerErrorCategory : public std::error_category {
|
|
public:
|
|
const char *name() const noexcept override { return "runtimedyld"; }
|
|
|
|
std::string message(int Condition) const override {
|
|
switch (static_cast<JITLinkErrorCode>(Condition)) {
|
|
case GenericJITLinkError:
|
|
return "Generic JITLink error";
|
|
}
|
|
llvm_unreachable("Unrecognized JITLinkErrorCode");
|
|
}
|
|
};
|
|
|
|
static ManagedStatic<JITLinkerErrorCategory> JITLinkerErrorCategory;
|
|
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
namespace jitlink {
|
|
|
|
char JITLinkError::ID = 0;
|
|
|
|
void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
|
|
|
|
std::error_code JITLinkError::convertToErrorCode() const {
|
|
return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory);
|
|
}
|
|
|
|
JITLinkMemoryManager::~JITLinkMemoryManager() = default;
|
|
|
|
JITLinkMemoryManager::Allocation::~Allocation() = default;
|
|
|
|
const StringRef getGenericEdgeKindName(Edge::Kind K) {
|
|
switch (K) {
|
|
case Edge::Invalid:
|
|
return "INVALID RELOCATION";
|
|
case Edge::KeepAlive:
|
|
return "Keep-Alive";
|
|
case Edge::LayoutNext:
|
|
return "Layout-Next";
|
|
default:
|
|
llvm_unreachable("Unrecognized relocation kind");
|
|
}
|
|
}
|
|
|
|
raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {
|
|
OS << "<";
|
|
if (A.getName().empty())
|
|
OS << "anon@" << format("0x%016" PRIx64, A.getAddress());
|
|
else
|
|
OS << A.getName();
|
|
OS << " [";
|
|
if (A.isDefined()) {
|
|
auto &DA = static_cast<const DefinedAtom &>(A);
|
|
OS << " section=" << DA.getSection().getName();
|
|
if (DA.isLive())
|
|
OS << " live";
|
|
if (DA.shouldDiscard())
|
|
OS << " should-discard";
|
|
} else
|
|
OS << " external";
|
|
OS << " ]>";
|
|
return OS;
|
|
}
|
|
|
|
void printEdge(raw_ostream &OS, const Atom &FixupAtom, const Edge &E,
|
|
StringRef EdgeKindName) {
|
|
OS << "edge@" << formatv("{0:x16}", FixupAtom.getAddress() + E.getOffset())
|
|
<< ": " << FixupAtom << " + " << E.getOffset() << " -- " << EdgeKindName
|
|
<< " -> " << E.getTarget() << " + " << E.getAddend();
|
|
}
|
|
|
|
Section::~Section() {
|
|
for (auto *DA : DefinedAtoms)
|
|
DA->~DefinedAtom();
|
|
}
|
|
|
|
void AtomGraph::dump(raw_ostream &OS,
|
|
std::function<StringRef(Edge::Kind)> EdgeKindToName) {
|
|
if (!EdgeKindToName)
|
|
EdgeKindToName = [](Edge::Kind K) { return StringRef(); };
|
|
|
|
OS << "Defined atoms:\n";
|
|
for (auto *DA : defined_atoms()) {
|
|
OS << " " << format("0x%016" PRIx64, DA->getAddress()) << ": " << *DA
|
|
<< "\n";
|
|
for (auto &E : DA->edges()) {
|
|
OS << " ";
|
|
StringRef EdgeName = (E.getKind() < Edge::FirstRelocation
|
|
? getGenericEdgeKindName(E.getKind())
|
|
: EdgeKindToName(E.getKind()));
|
|
|
|
if (!EdgeName.empty())
|
|
printEdge(OS, *DA, E, EdgeName);
|
|
else {
|
|
auto EdgeNumberString = std::to_string(E.getKind());
|
|
printEdge(OS, *DA, E, EdgeNumberString);
|
|
}
|
|
OS << "\n";
|
|
}
|
|
}
|
|
|
|
OS << "Absolute atoms:\n";
|
|
for (auto *A : absolute_atoms())
|
|
OS << " " << format("0x%016" PRIx64, A->getAddress()) << ": " << *A
|
|
<< "\n";
|
|
|
|
OS << "External atoms:\n";
|
|
for (auto *A : external_atoms())
|
|
OS << " " << format("0x%016" PRIx64, A->getAddress()) << ": " << *A
|
|
<< "\n";
|
|
}
|
|
|
|
Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
|
|
InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) {
|
|
|
|
using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
|
|
|
|
// Local class for allocation.
|
|
class IPMMAlloc : public Allocation {
|
|
public:
|
|
IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
|
|
MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
|
|
assert(SegBlocks.count(Seg) && "No allocation for segment");
|
|
return {static_cast<char *>(SegBlocks[Seg].base()),
|
|
SegBlocks[Seg].size()};
|
|
}
|
|
JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
|
|
assert(SegBlocks.count(Seg) && "No allocation for segment");
|
|
return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
|
|
}
|
|
void finalizeAsync(FinalizeContinuation OnFinalize) override {
|
|
OnFinalize(applyProtections());
|
|
}
|
|
Error deallocate() override {
|
|
for (auto &KV : SegBlocks)
|
|
if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
|
|
return errorCodeToError(EC);
|
|
return Error::success();
|
|
}
|
|
|
|
private:
|
|
Error applyProtections() {
|
|
for (auto &KV : SegBlocks) {
|
|
auto &Prot = KV.first;
|
|
auto &Block = KV.second;
|
|
if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
|
|
return errorCodeToError(EC);
|
|
if (Prot & sys::Memory::MF_EXEC)
|
|
sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
|
|
}
|
|
return Error::success();
|
|
}
|
|
|
|
AllocationMap SegBlocks;
|
|
};
|
|
|
|
AllocationMap Blocks;
|
|
const sys::Memory::ProtectionFlags ReadWrite =
|
|
static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
|
|
sys::Memory::MF_WRITE);
|
|
|
|
for (auto &KV : Request) {
|
|
auto &Seg = KV.second;
|
|
|
|
if (Seg.getContentAlignment() > sys::Process::getPageSize())
|
|
return make_error<StringError>("Cannot request higher than page "
|
|
"alignment",
|
|
inconvertibleErrorCode());
|
|
|
|
if (sys::Process::getPageSize() % Seg.getContentAlignment() != 0)
|
|
return make_error<StringError>("Page size is not a multiple of "
|
|
"alignment",
|
|
inconvertibleErrorCode());
|
|
|
|
uint64_t ZeroFillStart =
|
|
alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment());
|
|
uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
|
|
|
|
std::error_code EC;
|
|
auto SegMem =
|
|
sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC);
|
|
|
|
if (EC)
|
|
return errorCodeToError(EC);
|
|
|
|
// Zero out the zero-fill memory.
|
|
memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
|
|
Seg.getZeroFillSize());
|
|
|
|
// Record the block for this segment.
|
|
Blocks[KV.first] = std::move(SegMem);
|
|
}
|
|
return std::unique_ptr<InProcessMemoryManager::Allocation>(
|
|
new IPMMAlloc(std::move(Blocks)));
|
|
}
|
|
|
|
JITLinkContext::~JITLinkContext() {}
|
|
|
|
bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const {
|
|
return true;
|
|
}
|
|
|
|
AtomGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const {
|
|
return AtomGraphPassFunction();
|
|
}
|
|
|
|
Error JITLinkContext::modifyPassConfig(const Triple &TT,
|
|
PassConfiguration &Config) {
|
|
return Error::success();
|
|
}
|
|
|
|
Error markAllAtomsLive(AtomGraph &G) {
|
|
for (auto *DA : G.defined_atoms())
|
|
DA->setLive(true);
|
|
return Error::success();
|
|
}
|
|
|
|
void jitLink(std::unique_ptr<JITLinkContext> Ctx) {
|
|
auto Magic = identify_magic(Ctx->getObjectBuffer().getBuffer());
|
|
switch (Magic) {
|
|
case file_magic::macho_object:
|
|
return jitLink_MachO(std::move(Ctx));
|
|
default:
|
|
Ctx->notifyFailed(make_error<JITLinkError>("Unsupported file format"));
|
|
};
|
|
}
|
|
|
|
} // end namespace jitlink
|
|
} // end namespace llvm
|