Mercurial > hg > CbC > CbC_llvm
view unittests/ExecutionEngine/JITLink/MachO_x86_64_Tests.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
line wrap: on
line source
//===--------- 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(AtomGraph &, 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 = llvm::make_unique<TestJITLinkContext>( **TR, [&](AtomGraph &G) { RunGraphTest(G, (*TR)->getDisassembler()); }); JTCtx->externals() = std::move(Externals); jitLink_MachO_x86_64(std::move(JTCtx)); } protected: static void verifyIsPointerTo(AtomGraph &G, DefinedAtom &A, Atom &Target) { EXPECT_EQ(A.edges_size(), 1U) << "Incorrect number of edges for pointer"; if (A.edges_size() != 1U) return; auto &E = *A.edges().begin(); 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, A), HasValue(Target.getAddress())) << "Pointer does not point to target"; } static void verifyGOTLoad(AtomGraph &G, DefinedAtom &A, Edge &E, Atom &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 atom"; if (!E.getTarget().isDefined()) return; verifyIsPointerTo(G, static_cast<DefinedAtom &>(E.getTarget()), Target); } static void verifyCall(const MCDisassembler &Dis, AtomGraph &G, DefinedAtom &Caller, Edge &E, Atom &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 = Caller.getAddress() + E.getOffset(); uint64_t PCRelDelta = Callee.getAddress() - (FixupAddress + 4); EXPECT_THAT_EXPECTED( decodeImmediateOperand(Dis, Caller, 0, E.getOffset() - 1), HasValue(PCRelDelta)); } static void verifyIndirectCall(const MCDisassembler &Dis, AtomGraph &G, DefinedAtom &Caller, Edge &E, Atom &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 atom"; if (!E.getTarget().isDefined()) return; verifyIsPointerTo(G, static_cast<DefinedAtom &>(E.getTarget()), Callee); JITTargetAddress FixupAddress = Caller.getAddress() + E.getOffset(); uint64_t PCRelDelta = E.getTarget().getAddress() - (FixupAddress + 4); EXPECT_THAT_EXPECTED( decodeImmediateOperand(Dis, Caller, 3, E.getOffset() - 2), HasValue(PCRelDelta)); } static void verifyCallViaStub(const MCDisassembler &Dis, AtomGraph &G, DefinedAtom &Caller, Edge &E, Atom &Callee) { verifyCall(Dis, G, Caller, E, E.getTarget()); if (!E.getTarget().isDefined()) { ADD_FAILURE() << "Edge target is not a stub"; return; } auto &StubAtom = static_cast<DefinedAtom &>(E.getTarget()); EXPECT_EQ(StubAtom.edges_size(), 1U) << "Expected one edge from stub to target"; auto &StubEdge = *StubAtom.edges().begin(); verifyIndirectCall(Dis, G, static_cast<DefinedAtom &>(StubAtom), 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(), [](AtomGraph &G, const MCDisassembler &Dis) { // Name the atoms in the asm above. auto &Baz = atom(G, "_baz"); auto &Y = atom(G, "_y"); auto &Bar = definedAtom(G, "_bar"); auto &Foo = definedAtom(G, "_foo"); auto &Foo_1 = definedAtom(G, "_foo.1"); auto &Foo_2 = definedAtom(G, "_foo.2"); auto &X = definedAtom(G, "_x"); auto &P = definedAtom(G, "_p"); // Check unsigned reloc for _p { EXPECT_EQ(P.edges_size(), 1U) << "Unexpected number of relocations"; EXPECT_EQ(P.edges().begin()->getKind(), Pointer64) << "Unexpected edge kind for _p"; EXPECT_THAT_EXPECTED(readInt<uint64_t>(G, P), 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.edges_size(), 1U) << "Incorrect number of edges for bar"; EXPECT_EQ(Bar.edges().begin()->getKind(), Branch32) << "Unexpected edge kind for _bar"; verifyCallViaStub(Dis, G, Bar, *Bar.edges().begin(), Baz); } // Check that _foo is a direct call to _bar. { EXPECT_EQ(Foo.edges_size(), 1U) << "Incorrect number of edges for foo"; EXPECT_EQ(Foo.edges().begin()->getKind(), Branch32); verifyCall(Dis, G, Foo, *Foo.edges().begin(), Bar); } // Check .got load in _foo.1 { EXPECT_EQ(Foo_1.edges_size(), 1U) << "Incorrect number of edges for foo_1"; EXPECT_EQ(Foo_1.edges().begin()->getKind(), PCRel32); verifyGOTLoad(G, Foo_1, *Foo_1.edges().begin(), Y); } // Check PCRel ref to _p in _foo.2 { EXPECT_EQ(Foo_2.edges_size(), 1U) << "Incorrect number of edges for foo_2"; EXPECT_EQ(Foo_2.edges().begin()->getKind(), PCRel32); JITTargetAddress FixupAddress = Foo_2.getAddress() + Foo_2.edges().begin()->getOffset(); uint64_t PCRelDelta = P.getAddress() - (FixupAddress + 4); EXPECT_THAT_EXPECTED(decodeImmediateOperand(Dis, Foo_2, 4, 0), HasValue(PCRelDelta)) << "PCRel load does not reference expected target"; } }); }