|  | //===------ StubsTests.cpp - Unit tests for generic stub generation -------===// | 
|  | // | 
|  | // 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 "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/JITLink.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/aarch64.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/loongarch.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/x86.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/x86_64.h" | 
|  | #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" | 
|  | #include "llvm/Support/Memory.h" | 
|  |  | 
|  | #include "llvm/Testing/Support/Error.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::jitlink; | 
|  |  | 
|  | static std::pair<Symbol &, Symbol &> | 
|  | GenerateStub(LinkGraph &G, size_t PointerSize, Edge::Kind PointerEdgeKind) { | 
|  | auto &FuncSymbol = G.addAbsoluteSymbol("Func", orc::ExecutorAddr(0x2000), 0, | 
|  | Linkage::Strong, Scope::Default, true); | 
|  |  | 
|  | // Create a section for pointer symbols. | 
|  | auto &PointersSec = | 
|  | G.createSection("__pointers", orc::MemProt::Read | orc::MemProt::Write); | 
|  |  | 
|  | // Create a section for jump stubs symbols. | 
|  | auto &StubsSec = | 
|  | G.createSection("__stubs", orc::MemProt::Read | orc::MemProt::Write); | 
|  |  | 
|  | auto AnonymousPtrCreator = getAnonymousPointerCreator(G.getTargetTriple()); | 
|  | EXPECT_TRUE(AnonymousPtrCreator); | 
|  |  | 
|  | auto &PointerSym = AnonymousPtrCreator(G, PointersSec, &FuncSymbol, 0); | 
|  | EXPECT_EQ(std::distance(PointerSym.getBlock().edges().begin(), | 
|  | PointerSym.getBlock().edges().end()), | 
|  | 1U); | 
|  | auto &DeltaEdge = *PointerSym.getBlock().edges().begin(); | 
|  | EXPECT_EQ(DeltaEdge.getKind(), PointerEdgeKind); | 
|  | EXPECT_EQ(&DeltaEdge.getTarget(), &FuncSymbol); | 
|  | EXPECT_EQ(PointerSym.getBlock().getSize(), PointerSize); | 
|  | EXPECT_TRUE(all_of(PointerSym.getBlock().getContent(), | 
|  | [](char x) { return x == 0; })); | 
|  |  | 
|  | auto PtrJumpStubCreator = getPointerJumpStubCreator(G.getTargetTriple()); | 
|  | EXPECT_TRUE(PtrJumpStubCreator); | 
|  | auto &StubSym = PtrJumpStubCreator(G, StubsSec, PointerSym); | 
|  | return {PointerSym, StubSym}; | 
|  | } | 
|  |  | 
|  | TEST(StubsTest, StubsGeneration_x86_64) { | 
|  | const char PointerJumpStubContent[6] = { | 
|  | static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00}; | 
|  | LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), | 
|  | Triple("x86_64-apple-darwin"), SubtargetFeatures(), | 
|  | getGenericEdgeKindName); | 
|  | auto [PointerSym, StubSym] = GenerateStub(G, 8U, x86_64::Pointer64); | 
|  |  | 
|  | EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), | 
|  | StubSym.getBlock().edges().end()), | 
|  | 1U); | 
|  | auto &JumpEdge = *StubSym.getBlock().edges().begin(); | 
|  | EXPECT_EQ(JumpEdge.getKind(), x86_64::BranchPCRel32); | 
|  | EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(StubSym.getBlock().getContent(), | 
|  | ArrayRef<char>(PointerJumpStubContent)); | 
|  | } | 
|  |  | 
|  | TEST(StubsTest, StubsGeneration_aarch64) { | 
|  | const char PointerJumpStubContent[12] = { | 
|  | 0x10, 0x00, 0x00, (char)0x90u, // ADRP x16, <imm>@page21 | 
|  | 0x10, 0x02, 0x40, (char)0xf9u, // LDR x16, [x16, <imm>@pageoff12] | 
|  | 0x00, 0x02, 0x1f, (char)0xd6u  // BR  x16 | 
|  | }; | 
|  | LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), | 
|  | Triple("aarch64-linux-gnu"), SubtargetFeatures(), | 
|  | getGenericEdgeKindName); | 
|  | auto [PointerSym, StubSym] = GenerateStub(G, 8U, aarch64::Pointer64); | 
|  |  | 
|  | EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), | 
|  | StubSym.getBlock().edges().end()), | 
|  | 2U); | 
|  | auto &AdrpHighEdge = *StubSym.getBlock().edges().begin(); | 
|  | auto &LdrEdge = *++StubSym.getBlock().edges().begin(); | 
|  | EXPECT_EQ(AdrpHighEdge.getKind(), aarch64::Page21); | 
|  | EXPECT_EQ(&AdrpHighEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(LdrEdge.getKind(), aarch64::PageOffset12); | 
|  | EXPECT_EQ(&LdrEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(StubSym.getBlock().getContent(), | 
|  | ArrayRef<char>(PointerJumpStubContent)); | 
|  | } | 
|  |  | 
|  | TEST(StubsTest, StubsGeneration_x86) { | 
|  | const char PointerJumpStubContent[6] = { | 
|  | static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00}; | 
|  | LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), | 
|  | Triple("i386-unknown-linux-gnu"), SubtargetFeatures(), | 
|  | getGenericEdgeKindName); | 
|  | auto [PointerSym, StubSym] = GenerateStub(G, 4U, x86::Pointer32); | 
|  |  | 
|  | EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), | 
|  | StubSym.getBlock().edges().end()), | 
|  | 1U); | 
|  | auto &JumpEdge = *StubSym.getBlock().edges().begin(); | 
|  | EXPECT_EQ(JumpEdge.getKind(), x86::Pointer32); | 
|  | EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(StubSym.getBlock().getContent(), | 
|  | ArrayRef<char>(PointerJumpStubContent)); | 
|  | } | 
|  |  | 
|  | TEST(StubsTest, StubsGeneration_loongarch32) { | 
|  | const char PointerJumpStubContent[12] = { | 
|  | 0x14, | 
|  | 0x00, | 
|  | 0x00, | 
|  | 0x1a, // pcalau12i $t8, %page20(imm) | 
|  | static_cast<char>(0x94), | 
|  | 0x02, | 
|  | static_cast<char>(0x80), | 
|  | 0x28, // ld.d $t8, $t8, %pageoff12(imm) | 
|  | static_cast<char>(0x80), | 
|  | 0x02, | 
|  | 0x00, | 
|  | 0x4c // jr $t8 | 
|  | }; | 
|  | LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), | 
|  | Triple("loongarch32"), SubtargetFeatures(), | 
|  | getGenericEdgeKindName); | 
|  | auto [PointerSym, StubSym] = GenerateStub(G, 4U, loongarch::Pointer32); | 
|  |  | 
|  | EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), | 
|  | StubSym.getBlock().edges().end()), | 
|  | 2U); | 
|  | auto &PageHighEdge = *StubSym.getBlock().edges().begin(); | 
|  | auto &PageLowEdge = *++StubSym.getBlock().edges().begin(); | 
|  | EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20); | 
|  | EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12); | 
|  | EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(StubSym.getBlock().getContent(), | 
|  | ArrayRef<char>(PointerJumpStubContent)); | 
|  | } | 
|  |  | 
|  | TEST(StubsTest, StubsGeneration_loongarch64) { | 
|  | const char PointerJumpStubContent[12] = { | 
|  | 0x14, | 
|  | 0x00, | 
|  | 0x00, | 
|  | 0x1a, // pcalau12i $t8, %page20(imm) | 
|  | static_cast<char>(0x94), | 
|  | 0x02, | 
|  | static_cast<char>(0xc0), | 
|  | 0x28, // ld.d $t8, $t8, %pageoff12(imm) | 
|  | static_cast<char>(0x80), | 
|  | 0x02, | 
|  | 0x00, | 
|  | 0x4c // jr $t8 | 
|  | }; | 
|  |  | 
|  | LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), | 
|  | Triple("loongarch64"), SubtargetFeatures(), | 
|  | getGenericEdgeKindName); | 
|  | auto [PointerSym, StubSym] = GenerateStub(G, 8U, loongarch::Pointer64); | 
|  |  | 
|  | EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), | 
|  | StubSym.getBlock().edges().end()), | 
|  | 2U); | 
|  | auto &PageHighEdge = *StubSym.getBlock().edges().begin(); | 
|  | auto &PageLowEdge = *++StubSym.getBlock().edges().begin(); | 
|  | EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20); | 
|  | EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12); | 
|  | EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym); | 
|  | EXPECT_EQ(StubSym.getBlock().getContent(), | 
|  | ArrayRef<char>(PointerJumpStubContent)); | 
|  | } |