mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +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
|
set(LLVM_LINK_COMPONENTS
|
||||||
${LLVM_TARGETS_TO_BUILD}
|
${LLVM_TARGETS_TO_BUILD}
|
||||||
JITLink
|
JITLink
|
||||||
MC
|
|
||||||
MCDisassembler
|
|
||||||
MCParser
|
|
||||||
Object
|
Object
|
||||||
RuntimeDyld
|
RuntimeDyld
|
||||||
Support
|
Support
|
||||||
Target
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_llvm_unittest(JITLinkTests
|
add_llvm_unittest(JITLinkTests
|
||||||
JITLinkTestCommon.cpp
|
|
||||||
LinkGraphTests.cpp
|
LinkGraphTests.cpp
|
||||||
MachO_x86_64_Tests.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(JITLinkTests PRIVATE LLVMTestingSupport)
|
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