mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[JITLink] Remove relocation unit tests.
These tests were written before llvm-jitlink supported regression testing of relocation support. They are now redundant.
This commit is contained in:
parent
b6f80a70ba
commit
b52ac8615c
@ -1,19 +1,13 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
JITLink
|
||||
MC
|
||||
MCDisassembler
|
||||
MCParser
|
||||
Object
|
||||
RuntimeDyld
|
||||
Support
|
||||
Target
|
||||
)
|
||||
|
||||
add_llvm_unittest(JITLinkTests
|
||||
JITLinkTestCommon.cpp
|
||||
LinkGraphTests.cpp
|
||||
MachO_x86_64_Tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(JITLinkTests PRIVATE LLVMTestingSupport)
|
||||
|
@ -1,251 +0,0 @@
|
||||
//===------- JITLinkTestCommon.cpp - Common code for JITLink tests --------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "JITLinkTestCommon.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
|
||||
using namespace llvm::jitlink;
|
||||
namespace llvm {
|
||||
|
||||
Expected<std::unique_ptr<JITLinkTestCommon::TestResources>>
|
||||
JITLinkTestCommon::TestResources::Create(StringRef AsmSrc, StringRef TripleStr,
|
||||
bool PIC, bool LargeCodeModel,
|
||||
MCTargetOptions Options) {
|
||||
Error Err = Error::success();
|
||||
auto R = std::unique_ptr<TestResources>(new TestResources(
|
||||
AsmSrc, TripleStr, PIC, LargeCodeModel, std::move(Options), Err));
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
return std::move(R);
|
||||
}
|
||||
|
||||
MemoryBufferRef
|
||||
JITLinkTestCommon::TestResources::getTestObjectBufferRef() const {
|
||||
return MemoryBufferRef(StringRef(ObjBuffer.data(), ObjBuffer.size()),
|
||||
"Test object");
|
||||
}
|
||||
|
||||
JITLinkTestCommon::TestResources::TestResources(StringRef AsmSrc,
|
||||
StringRef TripleStr, bool PIC,
|
||||
bool LargeCodeModel,
|
||||
MCTargetOptions Options,
|
||||
Error &Err)
|
||||
: ObjStream(ObjBuffer), Options(std::move(Options)) {
|
||||
ErrorAsOutParameter _(&Err);
|
||||
Triple TT(Triple::normalize(TripleStr));
|
||||
if (auto Err2 = initializeTripleSpecifics(TT)) {
|
||||
Err = std::move(Err2);
|
||||
return;
|
||||
}
|
||||
initializeTestSpecifics(AsmSrc, TT, PIC, LargeCodeModel);
|
||||
}
|
||||
|
||||
Error JITLinkTestCommon::TestResources::initializeTripleSpecifics(Triple &TT) {
|
||||
std::string ErrorMsg;
|
||||
TheTarget = TargetRegistry::lookupTarget("", TT, ErrorMsg);
|
||||
|
||||
if (!TheTarget)
|
||||
return make_error<StringError>(ErrorMsg, inconvertibleErrorCode());
|
||||
|
||||
MRI.reset(TheTarget->createMCRegInfo(TT.getTriple()));
|
||||
if (!MRI)
|
||||
report_fatal_error("Could not build MCRegisterInfo for triple");
|
||||
|
||||
MCTargetOptions MCOptions;
|
||||
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TT.getTriple(), MCOptions));
|
||||
if (!MAI)
|
||||
report_fatal_error("Could not build MCAsmInfo for triple");
|
||||
|
||||
MCII.reset(TheTarget->createMCInstrInfo());
|
||||
if (!MCII)
|
||||
report_fatal_error("Could not build MCInstrInfo for triple");
|
||||
|
||||
STI.reset(TheTarget->createMCSubtargetInfo(TT.getTriple(), "", ""));
|
||||
if (!STI)
|
||||
report_fatal_error("Could not build MCSubtargetInfo for triple");
|
||||
|
||||
DisCtx = std::make_unique<MCContext>(MAI.get(), MRI.get(), nullptr);
|
||||
Dis.reset(TheTarget->createMCDisassembler(*STI, *DisCtx));
|
||||
|
||||
if (!Dis)
|
||||
report_fatal_error("Could not build MCDisassembler");
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void JITLinkTestCommon::TestResources::initializeTestSpecifics(
|
||||
StringRef AsmSrc, const Triple &TT, bool PIC, bool LargeCodeModel) {
|
||||
SrcMgr.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(AsmSrc), SMLoc());
|
||||
AsCtx = std::make_unique<MCContext>(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
|
||||
MOFI.InitMCObjectFileInfo(TT, PIC, *AsCtx, LargeCodeModel);
|
||||
|
||||
std::unique_ptr<MCCodeEmitter> CE(
|
||||
TheTarget->createMCCodeEmitter(*MCII, *MRI, *AsCtx));
|
||||
if (!CE)
|
||||
report_fatal_error("Could not build MCCodeEmitter");
|
||||
|
||||
std::unique_ptr<MCAsmBackend> MAB(
|
||||
TheTarget->createMCAsmBackend(*STI, *MRI, Options));
|
||||
if (!MAB)
|
||||
report_fatal_error("Could not build MCAsmBackend for test");
|
||||
|
||||
std::unique_ptr<MCObjectWriter> MOW(MAB->createObjectWriter(ObjStream));
|
||||
|
||||
MOS.reset(TheTarget->createMCObjectStreamer(
|
||||
TT, *AsCtx, std::move(MAB), std::move(MOW), std::move(CE), *STI,
|
||||
Options.MCRelaxAll, Options.MCIncrementalLinkerCompatible, false));
|
||||
|
||||
std::unique_ptr<MCAsmParser> MAP(
|
||||
createMCAsmParser(SrcMgr, *AsCtx, *MOS, *MAI));
|
||||
std::unique_ptr<MCTargetAsmParser> TAP(
|
||||
TheTarget->createMCAsmParser(*STI, *MAP, *MCII, Options));
|
||||
|
||||
if (!TAP)
|
||||
report_fatal_error("Could not build MCTargetAsmParser for test");
|
||||
|
||||
MAP->setTargetParser(*TAP);
|
||||
|
||||
if (MAP->Run(false))
|
||||
report_fatal_error("Failed to parse test case");
|
||||
}
|
||||
|
||||
JITLinkTestCommon::TestJITLinkContext::TestJITLinkContext(
|
||||
TestResources &TR, TestCaseFunction TestCase)
|
||||
: TR(TR), TestCase(std::move(TestCase)) {}
|
||||
|
||||
JITLinkTestCommon::TestJITLinkContext &
|
||||
JITLinkTestCommon::TestJITLinkContext::setMemoryManager(
|
||||
std::unique_ptr<JITLinkMemoryManager> MM) {
|
||||
assert(!MemMgr && "Memory manager already set");
|
||||
MemMgr = std::move(MM);
|
||||
return *this;
|
||||
}
|
||||
|
||||
JITLinkMemoryManager &
|
||||
JITLinkTestCommon::TestJITLinkContext::getMemoryManager() {
|
||||
if (!MemMgr)
|
||||
MemMgr = std::make_unique<InProcessMemoryManager>();
|
||||
return *MemMgr;
|
||||
}
|
||||
|
||||
MemoryBufferRef JITLinkTestCommon::TestJITLinkContext::getObjectBuffer() const {
|
||||
return TR.getTestObjectBufferRef();
|
||||
}
|
||||
|
||||
void JITLinkTestCommon::TestJITLinkContext::notifyFailed(Error Err) {
|
||||
ADD_FAILURE() << "Unexpected failure: " << toString(std::move(Err));
|
||||
}
|
||||
|
||||
void JITLinkTestCommon::TestJITLinkContext::lookup(
|
||||
const DenseSet<StringRef> &Symbols,
|
||||
std::unique_ptr<JITLinkAsyncLookupContinuation> LC) {
|
||||
jitlink::AsyncLookupResult LookupResult;
|
||||
DenseSet<StringRef> MissingSymbols;
|
||||
for (const auto &Symbol : Symbols) {
|
||||
auto I = Externals.find(Symbol);
|
||||
if (I != Externals.end())
|
||||
LookupResult[Symbol] = I->second;
|
||||
else
|
||||
MissingSymbols.insert(Symbol);
|
||||
}
|
||||
|
||||
if (MissingSymbols.empty())
|
||||
LC->run(std::move(LookupResult));
|
||||
else {
|
||||
std::string ErrMsg;
|
||||
{
|
||||
raw_string_ostream ErrMsgStream(ErrMsg);
|
||||
ErrMsgStream << "Failed to resolve external symbols: [";
|
||||
for (auto &Sym : MissingSymbols)
|
||||
ErrMsgStream << " " << Sym;
|
||||
ErrMsgStream << " ]\n";
|
||||
}
|
||||
LC->run(
|
||||
make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()));
|
||||
}
|
||||
}
|
||||
|
||||
void JITLinkTestCommon::TestJITLinkContext::notifyResolved(LinkGraph &G) {
|
||||
if (NotifyResolved)
|
||||
NotifyResolved(G);
|
||||
}
|
||||
|
||||
void JITLinkTestCommon::TestJITLinkContext::notifyFinalized(
|
||||
std::unique_ptr<JITLinkMemoryManager::Allocation> A) {
|
||||
if (NotifyFinalized)
|
||||
NotifyFinalized(std::move(A));
|
||||
}
|
||||
|
||||
Error JITLinkTestCommon::TestJITLinkContext::modifyPassConfig(
|
||||
const Triple &TT, PassConfiguration &Config) {
|
||||
if (TestCase)
|
||||
Config.PostFixupPasses.push_back([&](LinkGraph &G) -> Error {
|
||||
TestCase(G);
|
||||
return Error::success();
|
||||
});
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
JITLinkTestCommon::JITLinkTestCommon() { initializeLLVMTargets(); }
|
||||
|
||||
Expected<std::pair<MCInst, size_t>>
|
||||
JITLinkTestCommon::disassemble(const MCDisassembler &Dis, jitlink::Block &B,
|
||||
size_t Offset) {
|
||||
ArrayRef<uint8_t> InstBuffer(
|
||||
reinterpret_cast<const uint8_t *>(B.getContent().data()) + Offset,
|
||||
B.getContent().size() - Offset);
|
||||
|
||||
MCInst Inst;
|
||||
uint64_t InstSize;
|
||||
auto Status =
|
||||
Dis.getInstruction(Inst, InstSize, InstBuffer, 0, nulls(), nulls());
|
||||
|
||||
if (Status != MCDisassembler::Success)
|
||||
return make_error<StringError>("Could not disassemble instruction",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
return std::make_pair(Inst, InstSize);
|
||||
}
|
||||
|
||||
Expected<int64_t> JITLinkTestCommon::decodeImmediateOperand(
|
||||
const MCDisassembler &Dis, jitlink::Block &B, size_t OpIdx, size_t Offset) {
|
||||
auto InstAndSize = disassemble(Dis, B, Offset);
|
||||
if (!InstAndSize)
|
||||
return InstAndSize.takeError();
|
||||
|
||||
if (OpIdx >= InstAndSize->first.getNumOperands())
|
||||
return make_error<StringError>("Invalid operand index",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
auto &Op = InstAndSize->first.getOperand(OpIdx);
|
||||
|
||||
if (!Op.isImm())
|
||||
return make_error<StringError>("Operand at index is not immediate",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
return Op.getImm();
|
||||
}
|
||||
|
||||
bool JITLinkTestCommon::AreTargetsInitialized = false;
|
||||
|
||||
void JITLinkTestCommon::initializeLLVMTargets() {
|
||||
if (!AreTargetsInitialized) {
|
||||
InitializeAllTargets();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmParsers();
|
||||
InitializeAllAsmPrinters();
|
||||
InitializeAllDisassemblers();
|
||||
AreTargetsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
@ -1,209 +0,0 @@
|
||||
//===---- JITLinkTestCommon.h - Utilities for Orc Unit Tests ----*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Common utilities for JITLink unit tests.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKTESTCOMMON_H
|
||||
#define LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKTESTCOMMON_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/MC/MCObjectStreamer.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParser.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class JITLinkTestCommon {
|
||||
public:
|
||||
|
||||
class TestResources {
|
||||
public:
|
||||
static Expected<std::unique_ptr<TestResources>>
|
||||
Create(StringRef AsmSrc, StringRef TripleStr, bool PIC, bool LargeCodeModel,
|
||||
MCTargetOptions Options);
|
||||
|
||||
MemoryBufferRef getTestObjectBufferRef() const;
|
||||
|
||||
const MCDisassembler &getDisassembler() const { return *Dis; }
|
||||
|
||||
private:
|
||||
TestResources(StringRef AsmSrc, StringRef TripleStr, bool PIC,
|
||||
bool LargeCodeModel, MCTargetOptions Options, Error &Err);
|
||||
|
||||
Error initializeTripleSpecifics(Triple &TT);
|
||||
void initializeTestSpecifics(StringRef AsmSource, const Triple &TT,
|
||||
bool PIC, bool LargeCodeModel);
|
||||
|
||||
const Target *TheTarget = nullptr;
|
||||
SourceMgr SrcMgr;
|
||||
SmallVector<char, 0> ObjBuffer;
|
||||
raw_svector_ostream ObjStream;
|
||||
|
||||
MCTargetOptions Options;
|
||||
std::unique_ptr<MCRegisterInfo> MRI;
|
||||
std::unique_ptr<MCAsmInfo> MAI;
|
||||
std::unique_ptr<MCInstrInfo> MCII;
|
||||
std::unique_ptr<MCSubtargetInfo> STI;
|
||||
|
||||
MCObjectFileInfo MOFI;
|
||||
std::unique_ptr<MCContext> AsCtx;
|
||||
std::unique_ptr<MCStreamer> MOS;
|
||||
|
||||
std::unique_ptr<MCContext> DisCtx;
|
||||
std::unique_ptr<const MCDisassembler> Dis;
|
||||
};
|
||||
|
||||
class TestJITLinkContext : public jitlink::JITLinkContext {
|
||||
public:
|
||||
using TestCaseFunction = std::function<void(jitlink::LinkGraph &)>;
|
||||
|
||||
using NotifyResolvedFunction = std::function<void(jitlink::LinkGraph &G)>;
|
||||
|
||||
using NotifyFinalizedFunction = std::function<void(
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>)>;
|
||||
|
||||
TestJITLinkContext(TestResources &TR, TestCaseFunction TestCase);
|
||||
|
||||
StringMap<JITEvaluatedSymbol> &externals() { return Externals; }
|
||||
|
||||
TestJITLinkContext &
|
||||
setNotifyResolved(NotifyResolvedFunction NotifyResolved);
|
||||
|
||||
TestJITLinkContext &
|
||||
setNotifyFinalized(NotifyFinalizedFunction NotifyFinalized);
|
||||
|
||||
TestJITLinkContext &
|
||||
setMemoryManager(std::unique_ptr<jitlink::JITLinkMemoryManager> MM);
|
||||
|
||||
jitlink::JITLinkMemoryManager &getMemoryManager() override;
|
||||
|
||||
MemoryBufferRef getObjectBuffer() const override;
|
||||
|
||||
void notifyFailed(Error Err) override;
|
||||
|
||||
void lookup(
|
||||
const DenseSet<StringRef> &Symbols,
|
||||
std::unique_ptr<jitlink::JITLinkAsyncLookupContinuation> LC) override;
|
||||
|
||||
void notifyResolved(jitlink::LinkGraph &G) override;
|
||||
|
||||
void notifyFinalized(
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation> A) override;
|
||||
|
||||
Error modifyPassConfig(const Triple &TT,
|
||||
jitlink::PassConfiguration &Config) override;
|
||||
|
||||
private:
|
||||
TestResources &TR;
|
||||
TestCaseFunction TestCase;
|
||||
NotifyResolvedFunction NotifyResolved;
|
||||
NotifyFinalizedFunction NotifyFinalized;
|
||||
std::unique_ptr<MemoryBuffer> ObjBuffer;
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr;
|
||||
StringMap<JITEvaluatedSymbol> Externals;
|
||||
};
|
||||
|
||||
JITLinkTestCommon();
|
||||
|
||||
/// Get TestResources for this target/test.
|
||||
///
|
||||
/// If this method fails it is likely because the target is not supported in
|
||||
/// this build. The test should bail out without failing (possibly logging a
|
||||
/// diagnostic).
|
||||
Expected<std::unique_ptr<TestResources>>
|
||||
getTestResources(StringRef AsmSrc, StringRef Triple, bool PIC,
|
||||
bool LargeCodeModel, MCTargetOptions Options) const {
|
||||
return TestResources::Create(AsmSrc, Triple, PIC, LargeCodeModel,
|
||||
std::move(Options));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static Expected<T> readInt(jitlink::LinkGraph &G, jitlink::Block &B,
|
||||
size_t Offset = 0) {
|
||||
if (Offset + sizeof(T) > B.getSize())
|
||||
return make_error<StringError>("Reading past end of block content",
|
||||
inconvertibleErrorCode());
|
||||
return support::endian::read<T, 1>(B.getContent().data() + Offset,
|
||||
G.getEndianness());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static Expected<T> readInt(jitlink::LinkGraph &G, StringRef SymbolName,
|
||||
size_t Offset = 0) {
|
||||
for (auto *Sym : G.defined_symbols()) {
|
||||
if (Sym->getName() == SymbolName)
|
||||
return readInt<T>(G, Sym->getBlock(), Sym->getOffset() + Offset);
|
||||
}
|
||||
return make_error<StringError>("Symbol \"" + SymbolName + "\" not found",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
static Expected<std::pair<MCInst, size_t>>
|
||||
disassemble(const MCDisassembler &Dis, jitlink::Block &B, size_t Offset = 0);
|
||||
|
||||
static Expected<int64_t> decodeImmediateOperand(const MCDisassembler &Dis,
|
||||
jitlink::Block &B,
|
||||
size_t OpIdx,
|
||||
size_t Offset = 0);
|
||||
|
||||
static jitlink::Symbol &symbol(jitlink::LinkGraph &G, StringRef Name) {
|
||||
for (auto *Sym : G.defined_symbols())
|
||||
if (Sym->getName() == Name)
|
||||
return *Sym;
|
||||
for (auto *Sym : G.external_symbols())
|
||||
if (Sym->getName() == Name)
|
||||
return *Sym;
|
||||
for (auto *Sym : G.absolute_symbols())
|
||||
if (Sym->getName() == Name)
|
||||
return *Sym;
|
||||
llvm_unreachable("Name must reference a symbol");
|
||||
}
|
||||
|
||||
static JITTargetAddress symbolAddr(jitlink::LinkGraph &G, StringRef Name) {
|
||||
return symbol(G, Name).getAddress();
|
||||
}
|
||||
|
||||
template <typename PredT>
|
||||
static size_t countEdgesMatching(jitlink::Block &B, const PredT &Pred) {
|
||||
return std::count_if(B.edges().begin(), B.edges().end(), Pred);
|
||||
}
|
||||
|
||||
template <typename PredT>
|
||||
static size_t countEdgesMatching(jitlink::LinkGraph &G, StringRef Name,
|
||||
const PredT &Pred) {
|
||||
return countEdgesMatching(symbol(G, Name), Pred);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static bool AreTargetsInitialized;
|
||||
void initializeLLVMTargets();
|
||||
|
||||
DenseMap<StringRef, JITEvaluatedSymbol> Externals;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,232 +0,0 @@
|
||||
//===--------- MachO_x86_64.cpp - Tests for JITLink MachO/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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "JITLinkTestCommon.h"
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
|
||||
#include "llvm/Testing/Support/Error.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::jitlink;
|
||||
using namespace llvm::jitlink::MachO_x86_64_Edges;
|
||||
|
||||
namespace {
|
||||
|
||||
class JITLinkTest_MachO_x86_64 : public JITLinkTestCommon,
|
||||
public testing::Test {
|
||||
public:
|
||||
using BasicVerifyGraphFunction =
|
||||
std::function<void(LinkGraph &, const MCDisassembler &)>;
|
||||
|
||||
void runBasicVerifyGraphTest(StringRef AsmSrc, StringRef Triple,
|
||||
StringMap<JITEvaluatedSymbol> Externals,
|
||||
bool PIC, bool LargeCodeModel,
|
||||
MCTargetOptions Options,
|
||||
BasicVerifyGraphFunction RunGraphTest) {
|
||||
auto TR = getTestResources(AsmSrc, Triple, PIC, LargeCodeModel,
|
||||
std::move(Options));
|
||||
if (!TR) {
|
||||
dbgs() << "Skipping JITLInk unit test: " << toString(TR.takeError())
|
||||
<< "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
auto JTCtx = std::make_unique<TestJITLinkContext>(
|
||||
**TR, [&](LinkGraph &G) { RunGraphTest(G, (*TR)->getDisassembler()); });
|
||||
|
||||
JTCtx->externals() = std::move(Externals);
|
||||
|
||||
jitLink_MachO_x86_64(std::move(JTCtx));
|
||||
}
|
||||
|
||||
protected:
|
||||
static void verifyIsPointerTo(LinkGraph &G, Block &B, Symbol &Target) {
|
||||
EXPECT_EQ(B.edges_size(), 1U) << "Incorrect number of edges for pointer";
|
||||
if (B.edges_size() != 1U)
|
||||
return;
|
||||
auto &E = *B.edges().begin();
|
||||
EXPECT_EQ(E.getOffset(), 0U) << "Expected edge offset of zero";
|
||||
EXPECT_EQ(E.getKind(), Pointer64)
|
||||
<< "Expected pointer to have a pointer64 relocation";
|
||||
EXPECT_EQ(&E.getTarget(), &Target) << "Expected edge to point at target";
|
||||
EXPECT_THAT_EXPECTED(readInt<uint64_t>(G, B), HasValue(Target.getAddress()))
|
||||
<< "Pointer does not point to target";
|
||||
}
|
||||
|
||||
static void verifyGOTLoad(LinkGraph &G, Edge &E, Symbol &Target) {
|
||||
EXPECT_EQ(E.getAddend(), 0U) << "Expected GOT load to have a zero addend";
|
||||
EXPECT_TRUE(E.getTarget().isDefined())
|
||||
<< "GOT entry should be a defined symbol";
|
||||
if (!E.getTarget().isDefined())
|
||||
return;
|
||||
|
||||
verifyIsPointerTo(G, E.getTarget().getBlock(), Target);
|
||||
}
|
||||
|
||||
static void verifyCall(const MCDisassembler &Dis, LinkGraph &G,
|
||||
Block &CallerBlock, Edge &E, Symbol &Callee) {
|
||||
EXPECT_EQ(E.getKind(), Branch32) << "Edge is not a Branch32";
|
||||
EXPECT_EQ(E.getAddend(), 0U) << "Expected no addend on stub call";
|
||||
EXPECT_EQ(&E.getTarget(), &Callee)
|
||||
<< "Edge does not point at expected callee";
|
||||
|
||||
JITTargetAddress FixupAddress = CallerBlock.getAddress() + E.getOffset();
|
||||
uint64_t PCRelDelta = Callee.getAddress() - (FixupAddress + 4);
|
||||
|
||||
EXPECT_THAT_EXPECTED(
|
||||
decodeImmediateOperand(Dis, CallerBlock, 0, E.getOffset() - 1),
|
||||
HasValue(PCRelDelta));
|
||||
}
|
||||
|
||||
static void verifyIndirectCall(const MCDisassembler &Dis, LinkGraph &G,
|
||||
Block &CallerBlock, Edge &E, Symbol &Callee) {
|
||||
EXPECT_EQ(E.getKind(), PCRel32) << "Edge is not a PCRel32";
|
||||
EXPECT_EQ(E.getAddend(), 0) << "Expected no addend on stub cal";
|
||||
EXPECT_TRUE(E.getTarget().isDefined()) << "Target is not a defined symbol";
|
||||
if (!E.getTarget().isDefined())
|
||||
return;
|
||||
verifyIsPointerTo(G, E.getTarget().getBlock(), Callee);
|
||||
|
||||
JITTargetAddress FixupAddress = CallerBlock.getAddress() + E.getOffset();
|
||||
uint64_t PCRelDelta = E.getTarget().getAddress() - (FixupAddress + 4);
|
||||
|
||||
EXPECT_THAT_EXPECTED(
|
||||
decodeImmediateOperand(Dis, CallerBlock, 3, E.getOffset() - 2),
|
||||
HasValue(PCRelDelta));
|
||||
}
|
||||
|
||||
static void verifyCallViaStub(const MCDisassembler &Dis, LinkGraph &G,
|
||||
Block &CallerBlock, Edge &E, Symbol &Callee) {
|
||||
verifyCall(Dis, G, CallerBlock, E, E.getTarget());
|
||||
|
||||
if (!E.getTarget().isDefined()) {
|
||||
ADD_FAILURE() << "Edge target is not a stub";
|
||||
return;
|
||||
}
|
||||
|
||||
auto &StubBlock = E.getTarget().getBlock();
|
||||
EXPECT_EQ(StubBlock.edges_size(), 1U)
|
||||
<< "Expected one edge from stub to target";
|
||||
|
||||
auto &StubEdge = *StubBlock.edges().begin();
|
||||
|
||||
verifyIndirectCall(Dis, G, StubBlock, StubEdge, Callee);
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
// Test each operation on LegacyObjectTransformLayer.
|
||||
TEST_F(JITLinkTest_MachO_x86_64, BasicRelocations) {
|
||||
runBasicVerifyGraphTest(
|
||||
R"(
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.build_version macos, 10, 14
|
||||
.globl _bar
|
||||
.p2align 4, 0x90
|
||||
_bar:
|
||||
callq _baz
|
||||
|
||||
.globl _foo
|
||||
.p2align 4, 0x90
|
||||
_foo:
|
||||
callq _bar
|
||||
_foo.1:
|
||||
movq _y@GOTPCREL(%rip), %rcx
|
||||
_foo.2:
|
||||
movq _p(%rip), %rdx
|
||||
|
||||
.section __DATA,__data
|
||||
.globl _x
|
||||
.p2align 2
|
||||
_x:
|
||||
.long 42
|
||||
|
||||
.globl _p
|
||||
.p2align 3
|
||||
_p:
|
||||
.quad _x
|
||||
|
||||
.subsections_via_symbols)",
|
||||
"x86_64-apple-macosx10.14",
|
||||
{{"_y", JITEvaluatedSymbol(0xdeadbeef, JITSymbolFlags::Exported)},
|
||||
{"_baz", JITEvaluatedSymbol(0xcafef00d, JITSymbolFlags::Exported)}},
|
||||
true, false, MCTargetOptions(),
|
||||
[](LinkGraph &G, const MCDisassembler &Dis) {
|
||||
// Name the symbols in the asm above.
|
||||
auto &Baz = symbol(G, "_baz");
|
||||
auto &Y = symbol(G, "_y");
|
||||
auto &Bar = symbol(G, "_bar");
|
||||
auto &Foo = symbol(G, "_foo");
|
||||
auto &Foo_1 = symbol(G, "_foo.1");
|
||||
auto &Foo_2 = symbol(G, "_foo.2");
|
||||
auto &X = symbol(G, "_x");
|
||||
auto &P = symbol(G, "_p");
|
||||
|
||||
// Check unsigned reloc for _p
|
||||
{
|
||||
EXPECT_EQ(P.getBlock().edges_size(), 1U)
|
||||
<< "Unexpected number of relocations";
|
||||
EXPECT_EQ(P.getBlock().edges().begin()->getKind(), Pointer64)
|
||||
<< "Unexpected edge kind for _p";
|
||||
EXPECT_THAT_EXPECTED(readInt<uint64_t>(G, P.getBlock()),
|
||||
HasValue(X.getAddress()))
|
||||
<< "Unsigned relocation did not apply correctly";
|
||||
}
|
||||
|
||||
// Check that _bar is a call-via-stub to _baz.
|
||||
// This will check that the call goes to a stub, that the stub is an
|
||||
// indirect call, and that the pointer for the indirect call points to
|
||||
// baz.
|
||||
{
|
||||
EXPECT_EQ(Bar.getBlock().edges_size(), 1U)
|
||||
<< "Incorrect number of edges for bar";
|
||||
EXPECT_EQ(Bar.getBlock().edges().begin()->getKind(), Branch32)
|
||||
<< "Unexpected edge kind for _bar";
|
||||
verifyCallViaStub(Dis, G, Bar.getBlock(),
|
||||
*Bar.getBlock().edges().begin(), Baz);
|
||||
}
|
||||
|
||||
// Check that _foo is a direct call to _bar.
|
||||
{
|
||||
EXPECT_EQ(Foo.getBlock().edges_size(), 1U)
|
||||
<< "Incorrect number of edges for foo";
|
||||
EXPECT_EQ(Foo.getBlock().edges().begin()->getKind(), Branch32);
|
||||
verifyCall(Dis, G, Foo.getBlock(), *Foo.getBlock().edges().begin(),
|
||||
Bar);
|
||||
}
|
||||
|
||||
// Check .got load in _foo.1
|
||||
{
|
||||
EXPECT_EQ(Foo_1.getBlock().edges_size(), 1U)
|
||||
<< "Incorrect number of edges for foo_1";
|
||||
EXPECT_EQ(Foo_1.getBlock().edges().begin()->getKind(), PCRel32);
|
||||
verifyGOTLoad(G, *Foo_1.getBlock().edges().begin(), Y);
|
||||
}
|
||||
|
||||
// Check PCRel ref to _p in _foo.2
|
||||
{
|
||||
EXPECT_EQ(Foo_2.getBlock().edges_size(), 1U)
|
||||
<< "Incorrect number of edges for foo_2";
|
||||
EXPECT_EQ(Foo_2.getBlock().edges().begin()->getKind(), PCRel32);
|
||||
|
||||
JITTargetAddress FixupAddress =
|
||||
Foo_2.getBlock().getAddress() +
|
||||
Foo_2.getBlock().edges().begin()->getOffset();
|
||||
uint64_t PCRelDelta = P.getAddress() - (FixupAddress + 4);
|
||||
|
||||
EXPECT_THAT_EXPECTED(
|
||||
decodeImmediateOperand(Dis, Foo_2.getBlock(), 4, 0),
|
||||
HasValue(PCRelDelta))
|
||||
<< "PCRel load does not reference expected target";
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user