1
0
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:
Lang Hames 2019-10-30 13:16:37 -07:00
parent b6f80a70ba
commit b52ac8615c
4 changed files with 0 additions and 698 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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";
}
});
}