1 //===------ StubsTests.cpp - Unit tests for generic stub generation -------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/STLExtras.h" 10 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 11 #include "llvm/ExecutionEngine/JITLink/aarch64.h" 12 #include "llvm/ExecutionEngine/JITLink/i386.h" 13 #include "llvm/ExecutionEngine/JITLink/loongarch.h" 14 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 15 #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" 16 #include "llvm/Support/Memory.h" 17 18 #include "llvm/Testing/Support/Error.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 using namespace llvm::jitlink; 23 24 static std::pair<Symbol &, Symbol &> 25 GenerateStub(LinkGraph &G, size_t PointerSize, Edge::Kind PointerEdgeKind) { 26 auto &FuncSymbol = G.addAbsoluteSymbol("Func", orc::ExecutorAddr(0x2000), 0, 27 Linkage::Strong, Scope::Default, true); 28 29 // Create a section for pointer symbols. 30 auto &PointersSec = 31 G.createSection("__pointers", orc::MemProt::Read | orc::MemProt::Write); 32 33 // Create a section for jump stubs symbols. 34 auto &StubsSec = 35 G.createSection("__stubs", orc::MemProt::Read | orc::MemProt::Write); 36 37 auto AnonymousPtrCreator = getAnonymousPointerCreator(G.getTargetTriple()); 38 EXPECT_TRUE(AnonymousPtrCreator); 39 40 auto &PointerSym = AnonymousPtrCreator(G, PointersSec, &FuncSymbol, 0); 41 EXPECT_EQ(std::distance(PointerSym.getBlock().edges().begin(), 42 PointerSym.getBlock().edges().end()), 43 1U); 44 auto &DeltaEdge = *PointerSym.getBlock().edges().begin(); 45 EXPECT_EQ(DeltaEdge.getKind(), PointerEdgeKind); 46 EXPECT_EQ(&DeltaEdge.getTarget(), &FuncSymbol); 47 EXPECT_EQ(PointerSym.getBlock().getSize(), PointerSize); 48 EXPECT_TRUE(all_of(PointerSym.getBlock().getContent(), 49 [](char x) { return x == 0; })); 50 51 auto PtrJumpStubCreator = getPointerJumpStubCreator(G.getTargetTriple()); 52 EXPECT_TRUE(PtrJumpStubCreator); 53 auto &StubSym = PtrJumpStubCreator(G, StubsSec, PointerSym); 54 return {PointerSym, StubSym}; 55 } 56 57 TEST(StubsTest, StubsGeneration_x86_64) { 58 const char PointerJumpStubContent[6] = { 59 static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00}; 60 LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), 61 Triple("x86_64-apple-darwin"), SubtargetFeatures(), 62 getGenericEdgeKindName); 63 auto [PointerSym, StubSym] = GenerateStub(G, 8U, x86_64::Pointer64); 64 65 EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), 66 StubSym.getBlock().edges().end()), 67 1U); 68 auto &JumpEdge = *StubSym.getBlock().edges().begin(); 69 EXPECT_EQ(JumpEdge.getKind(), x86_64::BranchPCRel32); 70 EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym); 71 EXPECT_EQ(StubSym.getBlock().getContent(), 72 ArrayRef<char>(PointerJumpStubContent)); 73 } 74 75 TEST(StubsTest, StubsGeneration_aarch64) { 76 const char PointerJumpStubContent[12] = { 77 0x10, 0x00, 0x00, (char)0x90u, // ADRP x16, <imm>@page21 78 0x10, 0x02, 0x40, (char)0xf9u, // LDR x16, [x16, <imm>@pageoff12] 79 0x00, 0x02, 0x1f, (char)0xd6u // BR x16 80 }; 81 LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), 82 Triple("aarch64-linux-gnu"), SubtargetFeatures(), 83 getGenericEdgeKindName); 84 auto [PointerSym, StubSym] = GenerateStub(G, 8U, aarch64::Pointer64); 85 86 EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), 87 StubSym.getBlock().edges().end()), 88 2U); 89 auto &AdrpHighEdge = *StubSym.getBlock().edges().begin(); 90 auto &LdrEdge = *++StubSym.getBlock().edges().begin(); 91 EXPECT_EQ(AdrpHighEdge.getKind(), aarch64::Page21); 92 EXPECT_EQ(&AdrpHighEdge.getTarget(), &PointerSym); 93 EXPECT_EQ(LdrEdge.getKind(), aarch64::PageOffset12); 94 EXPECT_EQ(&LdrEdge.getTarget(), &PointerSym); 95 EXPECT_EQ(StubSym.getBlock().getContent(), 96 ArrayRef<char>(PointerJumpStubContent)); 97 } 98 99 TEST(StubsTest, StubsGeneration_i386) { 100 const char PointerJumpStubContent[6] = { 101 static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00}; 102 LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), 103 Triple("i386-unknown-linux-gnu"), SubtargetFeatures(), 104 getGenericEdgeKindName); 105 auto [PointerSym, StubSym] = GenerateStub(G, 4U, i386::Pointer32); 106 107 EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), 108 StubSym.getBlock().edges().end()), 109 1U); 110 auto &JumpEdge = *StubSym.getBlock().edges().begin(); 111 EXPECT_EQ(JumpEdge.getKind(), i386::Pointer32); 112 EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym); 113 EXPECT_EQ(StubSym.getBlock().getContent(), 114 ArrayRef<char>(PointerJumpStubContent)); 115 } 116 117 TEST(StubsTest, StubsGeneration_loongarch32) { 118 const char PointerJumpStubContent[12] = { 119 0x14, 120 0x00, 121 0x00, 122 0x1a, // pcalau12i $t8, %page20(imm) 123 static_cast<char>(0x94), 124 0x02, 125 static_cast<char>(0x80), 126 0x28, // ld.d $t8, $t8, %pageoff12(imm) 127 static_cast<char>(0x80), 128 0x02, 129 0x00, 130 0x4c // jr $t8 131 }; 132 LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), 133 Triple("loongarch32"), SubtargetFeatures(), 134 getGenericEdgeKindName); 135 auto [PointerSym, StubSym] = GenerateStub(G, 4U, loongarch::Pointer32); 136 137 EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), 138 StubSym.getBlock().edges().end()), 139 2U); 140 auto &PageHighEdge = *StubSym.getBlock().edges().begin(); 141 auto &PageLowEdge = *++StubSym.getBlock().edges().begin(); 142 EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20); 143 EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym); 144 EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12); 145 EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym); 146 EXPECT_EQ(StubSym.getBlock().getContent(), 147 ArrayRef<char>(PointerJumpStubContent)); 148 } 149 150 TEST(StubsTest, StubsGeneration_loongarch64) { 151 const char PointerJumpStubContent[12] = { 152 0x14, 153 0x00, 154 0x00, 155 0x1a, // pcalau12i $t8, %page20(imm) 156 static_cast<char>(0x94), 157 0x02, 158 static_cast<char>(0xc0), 159 0x28, // ld.d $t8, $t8, %pageoff12(imm) 160 static_cast<char>(0x80), 161 0x02, 162 0x00, 163 0x4c // jr $t8 164 }; 165 166 LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(), 167 Triple("loongarch64"), SubtargetFeatures(), 168 getGenericEdgeKindName); 169 auto [PointerSym, StubSym] = GenerateStub(G, 8U, loongarch::Pointer64); 170 171 EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(), 172 StubSym.getBlock().edges().end()), 173 2U); 174 auto &PageHighEdge = *StubSym.getBlock().edges().begin(); 175 auto &PageLowEdge = *++StubSym.getBlock().edges().begin(); 176 EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20); 177 EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym); 178 EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12); 179 EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym); 180 EXPECT_EQ(StubSym.getBlock().getContent(), 181 ArrayRef<char>(PointerJumpStubContent)); 182 } 183