1 //===------ LinkGraphTests.cpp - Unit tests for core JITLink classes ------===//
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/Support/Endian.h"
12 #include "llvm/Support/Memory.h"
13 #include "gtest/gtest.h"
14
15 using namespace llvm;
16 using namespace llvm::jitlink;
17
18 static auto RWFlags =
19 sys::Memory::ProtectionFlags(sys::Memory::MF_READ | sys::Memory::MF_WRITE);
20
TEST(LinkGraphTest,Construction)21 TEST(LinkGraphTest, Construction) {
22 // Check that LinkGraph construction works as expected.
23 LinkGraph G("foo", 8, support::little);
24 EXPECT_EQ(G.getName(), "foo");
25 EXPECT_EQ(G.getPointerSize(), 8U);
26 EXPECT_EQ(G.getEndianness(), support::little);
27 EXPECT_TRUE(llvm::empty(G.external_symbols()));
28 EXPECT_TRUE(llvm::empty(G.absolute_symbols()));
29 EXPECT_TRUE(llvm::empty(G.defined_symbols()));
30 EXPECT_TRUE(llvm::empty(G.blocks()));
31 }
32
TEST(LinkGraphTest,BlockAndSymbolIteration)33 TEST(LinkGraphTest, BlockAndSymbolIteration) {
34 // Check that we can iterate over blocks within Sections and across sections.
35
36 const char BlockContentBytes[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
37 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
38 0x1C, 0x1D, 0x1E, 0x1F, 0x00};
39 StringRef BlockContent(BlockContentBytes);
40
41 LinkGraph G("foo", 8, support::little);
42 auto &Sec1 = G.createSection("__data.1", RWFlags);
43 auto &B1 = G.createContentBlock(Sec1, BlockContent, 0x1000, 8, 0);
44 auto &B2 = G.createContentBlock(Sec1, BlockContent, 0x2000, 8, 0);
45 auto &S1 = G.addDefinedSymbol(B1, 0, "S1", 4, Linkage::Strong, Scope::Default,
46 false, false);
47 auto &S2 = G.addDefinedSymbol(B2, 4, "S2", 4, Linkage::Strong, Scope::Default,
48 false, false);
49
50 auto &Sec2 = G.createSection("__data.1", RWFlags);
51 auto &B3 = G.createContentBlock(Sec2, BlockContent, 0x3000, 8, 0);
52 auto &B4 = G.createContentBlock(Sec2, BlockContent, 0x4000, 8, 0);
53 auto &S3 = G.addDefinedSymbol(B3, 0, "S3", 4, Linkage::Strong, Scope::Default,
54 false, false);
55 auto &S4 = G.addDefinedSymbol(B4, 4, "S4", 4, Linkage::Strong, Scope::Default,
56 false, false);
57
58 // Check that iteration of blocks within a section behaves as expected.
59 EXPECT_EQ(std::distance(Sec1.blocks().begin(), Sec1.blocks().end()), 2);
60 EXPECT_TRUE(llvm::count(Sec1.blocks(), &B1));
61 EXPECT_TRUE(llvm::count(Sec1.blocks(), &B2));
62
63 // Check that iteration of symbols within a section behaves as expected.
64 EXPECT_EQ(std::distance(Sec1.symbols().begin(), Sec1.symbols().end()), 2);
65 EXPECT_TRUE(llvm::count(Sec1.symbols(), &S1));
66 EXPECT_TRUE(llvm::count(Sec1.symbols(), &S2));
67
68 // Check that iteration of blocks across sections behaves as expected.
69 EXPECT_EQ(std::distance(G.blocks().begin(), G.blocks().end()), 4);
70 EXPECT_TRUE(llvm::count(G.blocks(), &B1));
71 EXPECT_TRUE(llvm::count(G.blocks(), &B2));
72 EXPECT_TRUE(llvm::count(G.blocks(), &B3));
73 EXPECT_TRUE(llvm::count(G.blocks(), &B4));
74
75 // Check that iteration of defined symbols across sections behaves as
76 // expected.
77 EXPECT_EQ(
78 std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 4);
79 EXPECT_TRUE(llvm::count(G.defined_symbols(), &S1));
80 EXPECT_TRUE(llvm::count(G.defined_symbols(), &S2));
81 EXPECT_TRUE(llvm::count(G.defined_symbols(), &S3));
82 EXPECT_TRUE(llvm::count(G.defined_symbols(), &S4));
83 }
84
TEST(LinkGraphTest,SplitBlock)85 TEST(LinkGraphTest, SplitBlock) {
86 // Check that the LinkGraph::splitBlock test works as expected.
87
88 const char BlockContentBytes[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
89 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
90 0x1C, 0x1D, 0x1E, 0x1F, 0x00};
91 StringRef BlockContent(BlockContentBytes);
92
93 LinkGraph G("foo", 8, support::little);
94 auto &Sec = G.createSection("__data", RWFlags);
95
96 // Create the block to split.
97 auto &B1 = G.createContentBlock(Sec, BlockContent, 0x1000, 8, 0);
98
99 // Add some symbols to the block.
100 auto &S1 = G.addDefinedSymbol(B1, 0, "S1", 4, Linkage::Strong, Scope::Default,
101 false, false);
102 auto &S2 = G.addDefinedSymbol(B1, 4, "S2", 4, Linkage::Strong, Scope::Default,
103 false, false);
104 auto &S3 = G.addDefinedSymbol(B1, 8, "S3", 4, Linkage::Strong, Scope::Default,
105 false, false);
106 auto &S4 = G.addDefinedSymbol(B1, 12, "S4", 4, Linkage::Strong,
107 Scope::Default, false, false);
108
109 // Add an extra block, EB, and target symbols, and use these to add edges
110 // from B1 to EB.
111 auto &EB = G.createContentBlock(Sec, BlockContent, 0x2000, 8, 0);
112 auto &ES1 = G.addDefinedSymbol(EB, 0, "TS1", 4, Linkage::Strong,
113 Scope::Default, false, false);
114 auto &ES2 = G.addDefinedSymbol(EB, 4, "TS2", 4, Linkage::Strong,
115 Scope::Default, false, false);
116 auto &ES3 = G.addDefinedSymbol(EB, 8, "TS3", 4, Linkage::Strong,
117 Scope::Default, false, false);
118 auto &ES4 = G.addDefinedSymbol(EB, 12, "TS4", 4, Linkage::Strong,
119 Scope::Default, false, false);
120
121 // Add edges from B1 to EB.
122 B1.addEdge(Edge::FirstRelocation, 0, ES1, 0);
123 B1.addEdge(Edge::FirstRelocation, 4, ES2, 0);
124 B1.addEdge(Edge::FirstRelocation, 8, ES3, 0);
125 B1.addEdge(Edge::FirstRelocation, 12, ES4, 0);
126
127 // Split B1.
128 auto &B2 = G.splitBlock(B1, 8);
129
130 // Check that the block addresses and content matches what we would expect.
131 EXPECT_EQ(B1.getAddress(), 0x1008U);
132 EXPECT_EQ(B1.getContent(), BlockContent.substr(8));
133
134 EXPECT_EQ(B2.getAddress(), 0x1000U);
135 EXPECT_EQ(B2.getContent(), BlockContent.substr(0, 8));
136
137 // Check that symbols in B1 were transferred as expected:
138 // We expect S1 and S2 to have been transferred to B2, and S3 and S4 to have
139 // remained attached to B1. Symbols S3 and S4 should have had their offsets
140 // slid to account for the change in address of B2.
141 EXPECT_EQ(&S1.getBlock(), &B2);
142 EXPECT_EQ(S1.getOffset(), 0U);
143
144 EXPECT_EQ(&S2.getBlock(), &B2);
145 EXPECT_EQ(S2.getOffset(), 4U);
146
147 EXPECT_EQ(&S3.getBlock(), &B1);
148 EXPECT_EQ(S3.getOffset(), 0U);
149
150 EXPECT_EQ(&S4.getBlock(), &B1);
151 EXPECT_EQ(S4.getOffset(), 4U);
152
153 // Check that edges in B1 have been transferred as expected:
154 // Both blocks should now have two edges each at offsets 0 and 4.
155 EXPECT_EQ(llvm::size(B1.edges()), 2);
156 if (size(B1.edges()) == 2) {
157 auto *E1 = &*B1.edges().begin();
158 auto *E2 = &*(B1.edges().begin() + 1);
159 if (E2->getOffset() < E1->getOffset())
160 std::swap(E1, E2);
161 EXPECT_EQ(E1->getOffset(), 0U);
162 EXPECT_EQ(E2->getOffset(), 4U);
163 }
164
165 EXPECT_EQ(llvm::size(B2.edges()), 2);
166 if (size(B2.edges()) == 2) {
167 auto *E1 = &*B2.edges().begin();
168 auto *E2 = &*(B2.edges().begin() + 1);
169 if (E2->getOffset() < E1->getOffset())
170 std::swap(E1, E2);
171 EXPECT_EQ(E1->getOffset(), 0U);
172 EXPECT_EQ(E2->getOffset(), 4U);
173 }
174 }
175