xref: /llvm-project/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp (revision 4eaff6c58ae2f130ac8d63cf2c87bbb483114876)
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