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/ExecutionEngine/Orc/ObjectFileInterface.h" |
12 | #include "llvm/Support/Memory.h" |
13 | |
14 | #include "llvm/Testing/Support/Error.h" |
15 | #include "gtest/gtest.h" |
16 | |
17 | using namespace llvm; |
18 | using namespace llvm::jitlink; |
19 | |
20 | static const char BlockContentBytes[] = { |
21 | 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6d, 0x6f, |
22 | 0x76, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, |
23 | 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x66, |
24 | 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6f, 0x72, 0x64, 0x20, |
25 | 0x68, 0x61, 0x64, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x61, |
26 | 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x0a, 0x54, 0x68, 0x61, 0x74, 0x20, 0x74, |
27 | 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6c, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, |
28 | 0x20, 0x4f, 0x6c, 0x64, 0x20, 0x52, 0x65, 0x67, 0x72, 0x65, 0x74, 0x20, |
29 | 0x68, 0x61, 0x64, 0x20, 0x67, 0x6f, 0x74, 0x20, 0x61, 0x77, 0x61, 0x79, |
30 | 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6a, 0x6f, |
31 | 0x69, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, 0x6c, |
32 | 0x64, 0x20, 0x62, 0x75, 0x73, 0x68, 0x20, 0x68, 0x6f, 0x72, 0x73, 0x65, |
33 | 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, |
34 | 0x77, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x61, 0x20, 0x74, 0x68, 0x6f, 0x75, |
35 | 0x73, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x2c, 0x0a, |
36 | 0x53, 0x6f, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, |
37 | 0x72, 0x61, 0x63, 0x6b, 0x73, 0x20, 0x68, 0x61, 0x64, 0x20, 0x67, 0x61, |
38 | 0x74, 0x68, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, |
39 | 0x65, 0x20, 0x66, 0x72, 0x61, 0x79, 0x2e, 0x0a, 0x41, 0x6c, 0x6c, 0x20, |
40 | 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x61, 0x6e, |
41 | 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x65, 0x64, 0x20, 0x72, 0x69, 0x64, 0x65, |
42 | 0x72, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, |
43 | 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6e, 0x65, 0x61, |
44 | 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x61, 0x72, 0x0a, 0x48, 0x61, |
45 | 0x64, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, |
46 | 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, |
47 | 0x65, 0x61, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x69, 0x67, 0x68, |
48 | 0x74, 0x2c, 0x0a, 0x46, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, |
49 | 0x75, 0x73, 0x68, 0x6d, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x20, |
50 | 0x68, 0x61, 0x72, 0x64, 0x20, 0x72, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, |
51 | 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, |
52 | 0x6c, 0x64, 0x20, 0x62, 0x75, 0x73, 0x68, 0x20, 0x68, 0x6f, 0x72, 0x73, |
53 | 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, |
54 | 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x2d, 0x68, 0x6f, |
55 | 0x72, 0x73, 0x65, 0x20, 0x73, 0x6e, 0x75, 0x66, 0x66, 0x73, 0x20, 0x74, |
56 | 0x68, 0x65, 0x20, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x20, 0x77, 0x69, |
57 | 0x74, 0x68, 0x20, 0x64, 0x65, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x00}; |
58 | |
59 | static ArrayRef<char> BlockContent(BlockContentBytes); |
60 | |
61 | TEST(LinkGraphTest, Construction) { |
62 | // Check that LinkGraph construction works as expected. |
63 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
64 | getGenericEdgeKindName); |
65 | EXPECT_EQ(G.getName(), "foo" ); |
66 | EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin" ); |
67 | EXPECT_EQ(G.getPointerSize(), 8U); |
68 | EXPECT_EQ(G.getEndianness(), llvm::endianness::little); |
69 | EXPECT_TRUE(G.external_symbols().empty()); |
70 | EXPECT_TRUE(G.absolute_symbols().empty()); |
71 | EXPECT_TRUE(G.defined_symbols().empty()); |
72 | EXPECT_TRUE(G.blocks().empty()); |
73 | } |
74 | |
75 | TEST(LinkGraphTest, AddressAccess) { |
76 | // Check that we can get addresses for blocks, symbols, and edges. |
77 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
78 | getGenericEdgeKindName); |
79 | |
80 | auto &Sec1 = |
81 | G.createSection(Name: "__data.1" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
82 | orc::ExecutorAddr B1Addr(0x1000); |
83 | auto &B1 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
84 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 4, Name: "S1" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
85 | IsCallable: false, IsLive: false); |
86 | B1.addEdge(K: Edge::FirstRelocation, Offset: 8, Target&: S1, Addend: 0); |
87 | auto &E1 = *B1.edges().begin(); |
88 | |
89 | EXPECT_EQ(B1.getAddress(), B1Addr) << "Incorrect block address" ; |
90 | EXPECT_EQ(S1.getAddress(), B1Addr + 4) << "Incorrect symbol address" ; |
91 | EXPECT_EQ(B1.getFixupAddress(E1), B1Addr + 8) << "Incorrect fixup address" ; |
92 | } |
93 | |
94 | TEST(LinkGraphTest, SectionEmpty) { |
95 | // Check that Section::empty behaves as expected. |
96 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
97 | getGenericEdgeKindName); |
98 | auto &Sec1 = |
99 | G.createSection(Name: "__data.1" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
100 | auto &B = |
101 | G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: orc::ExecutorAddr(0x1000), Alignment: 8, AlignmentOffset: 0); |
102 | G.addDefinedSymbol(Content&: B, Offset: 0, Name: "S" , Size: 4, L: Linkage::Strong, S: Scope::Default, IsCallable: false, |
103 | IsLive: false); |
104 | |
105 | auto &Sec2 = |
106 | G.createSection(Name: "__data.2" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
107 | |
108 | EXPECT_FALSE(Sec1.empty()); |
109 | EXPECT_TRUE(Sec2.empty()); |
110 | } |
111 | |
112 | TEST(LinkGraphTest, BlockAndSymbolIteration) { |
113 | // Check that we can iterate over blocks within Sections and across sections. |
114 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
115 | getGenericEdgeKindName); |
116 | auto &Sec1 = |
117 | G.createSection(Name: "__data.1" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
118 | orc::ExecutorAddr B1Addr(0x1000); |
119 | auto &B1 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
120 | orc::ExecutorAddr B2Addr(0x2000); |
121 | auto &B2 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B2Addr, Alignment: 8, AlignmentOffset: 0); |
122 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
123 | IsCallable: false, IsLive: false); |
124 | auto &S2 = G.addDefinedSymbol(Content&: B2, Offset: 4, Name: "S2" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
125 | IsCallable: false, IsLive: false); |
126 | |
127 | auto &Sec2 = |
128 | G.createSection(Name: "__data.2" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
129 | orc::ExecutorAddr B3Addr(0x3000); |
130 | auto &B3 = G.createContentBlock(Parent&: Sec2, Content: BlockContent, Address: B3Addr, Alignment: 8, AlignmentOffset: 0); |
131 | orc::ExecutorAddr B4Addr(0x4000); |
132 | auto &B4 = G.createContentBlock(Parent&: Sec2, Content: BlockContent, Address: B4Addr, Alignment: 8, AlignmentOffset: 0); |
133 | auto &S3 = G.addDefinedSymbol(Content&: B3, Offset: 0, Name: "S3" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
134 | IsCallable: false, IsLive: false); |
135 | auto &S4 = G.addDefinedSymbol(Content&: B4, Offset: 4, Name: "S4" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
136 | IsCallable: false, IsLive: false); |
137 | |
138 | // Check that iteration of blocks within a section behaves as expected. |
139 | EXPECT_EQ(std::distance(Sec1.blocks().begin(), Sec1.blocks().end()), 2); |
140 | EXPECT_TRUE(llvm::count(Sec1.blocks(), &B1)); |
141 | EXPECT_TRUE(llvm::count(Sec1.blocks(), &B2)); |
142 | |
143 | // Check that iteration of symbols within a section behaves as expected. |
144 | EXPECT_EQ(std::distance(Sec1.symbols().begin(), Sec1.symbols().end()), 2); |
145 | EXPECT_TRUE(llvm::count(Sec1.symbols(), &S1)); |
146 | EXPECT_TRUE(llvm::count(Sec1.symbols(), &S2)); |
147 | |
148 | // Check that iteration of blocks across sections behaves as expected. |
149 | EXPECT_EQ(std::distance(G.blocks().begin(), G.blocks().end()), 4); |
150 | EXPECT_TRUE(llvm::count(G.blocks(), &B1)); |
151 | EXPECT_TRUE(llvm::count(G.blocks(), &B2)); |
152 | EXPECT_TRUE(llvm::count(G.blocks(), &B3)); |
153 | EXPECT_TRUE(llvm::count(G.blocks(), &B4)); |
154 | |
155 | // Check that iteration of defined symbols across sections behaves as |
156 | // expected. |
157 | EXPECT_EQ( |
158 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 4); |
159 | EXPECT_TRUE(llvm::count(G.defined_symbols(), &S1)); |
160 | EXPECT_TRUE(llvm::count(G.defined_symbols(), &S2)); |
161 | EXPECT_TRUE(llvm::count(G.defined_symbols(), &S3)); |
162 | EXPECT_TRUE(llvm::count(G.defined_symbols(), &S4)); |
163 | } |
164 | |
165 | TEST(LinkGraphTest, ContentAccessAndUpdate) { |
166 | // Check that we can make a defined symbol external. |
167 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
168 | getGenericEdgeKindName); |
169 | auto &Sec = |
170 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
171 | |
172 | // Create an initial block. |
173 | orc::ExecutorAddr BAddr(0x1000); |
174 | auto &B = G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: BAddr, Alignment: 8, AlignmentOffset: 0); |
175 | |
176 | EXPECT_FALSE(B.isContentMutable()) << "Content unexpectedly mutable" ; |
177 | EXPECT_EQ(B.getContent().data(), BlockContent.data()) |
178 | << "Unexpected block content data pointer" ; |
179 | EXPECT_EQ(B.getContent().size(), BlockContent.size()) |
180 | << "Unexpected block content size" ; |
181 | |
182 | // Expect that attempting to get already-mutable content fails if the |
183 | // content is not yet mutable (debug builds only). |
184 | #ifndef NDEBUG |
185 | EXPECT_DEATH({ (void)B.getAlreadyMutableContent(); }, |
186 | "Content is not mutable" ) |
187 | << "Unexpected mutable access allowed to immutable data" ; |
188 | #endif |
189 | |
190 | // Check that mutable content is copied on request as expected. |
191 | auto MutableContent = B.getMutableContent(G); |
192 | EXPECT_TRUE(B.isContentMutable()) << "Content unexpectedly immutable" ; |
193 | EXPECT_NE(MutableContent.data(), BlockContent.data()) |
194 | << "Unexpected mutable content data pointer" ; |
195 | EXPECT_EQ(MutableContent.size(), BlockContent.size()) |
196 | << "Unexpected mutable content size" ; |
197 | EXPECT_TRUE(std::equal(MutableContent.begin(), MutableContent.end(), |
198 | BlockContent.begin())) |
199 | << "Unexpected mutable content value" ; |
200 | |
201 | // Check that already-mutable content behaves as expected, with no |
202 | // further copies. |
203 | auto MutableContent2 = B.getMutableContent(G); |
204 | EXPECT_TRUE(B.isContentMutable()) << "Content unexpectedly immutable" ; |
205 | EXPECT_EQ(MutableContent2.data(), MutableContent.data()) |
206 | << "Unexpected mutable content 2 data pointer" ; |
207 | EXPECT_EQ(MutableContent2.size(), MutableContent.size()) |
208 | << "Unexpected mutable content 2 size" ; |
209 | |
210 | // Check that getAlreadyMutableContent behaves as expected, with no |
211 | // further copies. |
212 | auto MutableContent3 = B.getMutableContent(G); |
213 | EXPECT_TRUE(B.isContentMutable()) << "Content unexpectedly immutable" ; |
214 | EXPECT_EQ(MutableContent3.data(), MutableContent.data()) |
215 | << "Unexpected mutable content 2 data pointer" ; |
216 | EXPECT_EQ(MutableContent3.size(), MutableContent.size()) |
217 | << "Unexpected mutable content 2 size" ; |
218 | |
219 | // Check that we can obtain a writer and reader over the content. |
220 | // Check that we can get a BinaryStreamReader for B. |
221 | auto Writer = G.getBlockContentWriter(B); |
222 | EXPECT_THAT_ERROR(Writer.writeInteger((uint32_t)0xcafef00d), Succeeded()); |
223 | |
224 | auto Reader = G.getBlockContentReader(B); |
225 | uint32_t Initial32Bits = 0; |
226 | EXPECT_THAT_ERROR(Reader.readInteger(Initial32Bits), Succeeded()); |
227 | EXPECT_EQ(Initial32Bits, (uint32_t)0xcafef00d); |
228 | |
229 | // Set content back to immutable and check that everything behaves as |
230 | // expected again. |
231 | B.setContent(BlockContent); |
232 | EXPECT_FALSE(B.isContentMutable()) << "Content unexpectedly mutable" ; |
233 | EXPECT_EQ(B.getContent().data(), BlockContent.data()) |
234 | << "Unexpected block content data pointer" ; |
235 | EXPECT_EQ(B.getContent().size(), BlockContent.size()) |
236 | << "Unexpected block content size" ; |
237 | |
238 | // Create an initially mutable block. |
239 | auto &B2 = G.createMutableContentBlock(Parent&: Sec, MutableContent, |
240 | Address: orc::ExecutorAddr(0x10000), Alignment: 8, AlignmentOffset: 0); |
241 | |
242 | EXPECT_TRUE(B2.isContentMutable()) << "Expected B2 content to be mutable" ; |
243 | EXPECT_EQ(B2.getSize(), MutableContent.size()); |
244 | |
245 | // Create a mutable content block with initial zero-fill. |
246 | auto &B3 = |
247 | G.createMutableContentBlock(Parent&: Sec, ContentSize: 16, Address: orc::ExecutorAddr(0x2000), Alignment: 8, AlignmentOffset: 0); |
248 | EXPECT_TRUE(B3.isContentMutable()) << "Expected B2 content to be mutable" ; |
249 | EXPECT_EQ(B3.getSize(), 16U); |
250 | EXPECT_TRUE(llvm::all_of(B3.getAlreadyMutableContent(), |
251 | [](char C) { return C == 0; })); |
252 | } |
253 | |
254 | TEST(LinkGraphTest, MakeExternal) { |
255 | // Check that we can make defined and absolute symbols external. |
256 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
257 | getGenericEdgeKindName); |
258 | auto &Sec = |
259 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
260 | |
261 | // Create an initial block. |
262 | auto &B1 = |
263 | G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: orc::ExecutorAddr(0x1000), Alignment: 8, AlignmentOffset: 0); |
264 | |
265 | // Add a symbol to the block. |
266 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
267 | IsCallable: false, IsLive: false); |
268 | |
269 | EXPECT_TRUE(S1.isDefined()) << "Symbol should be defined" ; |
270 | EXPECT_FALSE(S1.isExternal()) << "Symbol should not be external" ; |
271 | EXPECT_FALSE(S1.isAbsolute()) << "Symbol should not be absolute" ; |
272 | EXPECT_TRUE(&S1.getBlock()) << "Symbol should have a non-null block" ; |
273 | EXPECT_EQ(S1.getAddress(), orc::ExecutorAddr(0x1000)) |
274 | << "Unexpected symbol address" ; |
275 | |
276 | EXPECT_EQ( |
277 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 1U) |
278 | << "Unexpected number of defined symbols" ; |
279 | EXPECT_EQ( |
280 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
281 | 0U) |
282 | << "Unexpected number of external symbols" ; |
283 | |
284 | // Add an absolute symbol. |
285 | auto &S2 = G.addAbsoluteSymbol(Name: "S2" , Address: orc::ExecutorAddr(0x2000), Size: 0, |
286 | L: Linkage::Strong, S: Scope::Default, IsLive: true); |
287 | |
288 | EXPECT_TRUE(S2.isAbsolute()) << "Symbol should be absolute" ; |
289 | EXPECT_EQ( |
290 | std::distance(G.absolute_symbols().begin(), G.absolute_symbols().end()), |
291 | 1U) |
292 | << "Unexpected number of symbols" ; |
293 | |
294 | // Make S1 and S2 external, confirm that the its flags are updated and that it |
295 | // is moved from the defined/absolute symbols lists to the externals list. |
296 | G.makeExternal(Sym&: S1); |
297 | G.makeExternal(Sym&: S2); |
298 | |
299 | EXPECT_FALSE(S1.isDefined()) << "Symbol should not be defined" ; |
300 | EXPECT_TRUE(S1.isExternal()) << "Symbol should be external" ; |
301 | EXPECT_FALSE(S1.isAbsolute()) << "Symbol should not be absolute" ; |
302 | EXPECT_FALSE(S2.isDefined()) << "Symbol should not be defined" ; |
303 | EXPECT_TRUE(S2.isExternal()) << "Symbol should be external" ; |
304 | EXPECT_FALSE(S2.isAbsolute()) << "Symbol should not be absolute" ; |
305 | |
306 | EXPECT_EQ(S1.getAddress(), orc::ExecutorAddr()) |
307 | << "Unexpected symbol address" ; |
308 | EXPECT_EQ(S2.getAddress(), orc::ExecutorAddr()) |
309 | << "Unexpected symbol address" ; |
310 | |
311 | EXPECT_EQ( |
312 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 0U) |
313 | << "Unexpected number of defined symbols" ; |
314 | EXPECT_EQ( |
315 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
316 | 2U) |
317 | << "Unexpected number of external symbols" ; |
318 | EXPECT_EQ( |
319 | std::distance(G.absolute_symbols().begin(), G.absolute_symbols().end()), |
320 | 0U) |
321 | << "Unexpected number of external symbols" ; |
322 | } |
323 | |
324 | TEST(LinkGraphTest, MakeAbsolute) { |
325 | // Check that we can make defined and external symbols absolute. |
326 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
327 | getGenericEdgeKindName); |
328 | auto &Sec = |
329 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
330 | |
331 | // Create an initial block. |
332 | auto &B1 = |
333 | G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: orc::ExecutorAddr(0x1000), Alignment: 8, AlignmentOffset: 0); |
334 | |
335 | // Add a symbol to the block. |
336 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
337 | IsCallable: false, IsLive: false); |
338 | |
339 | EXPECT_TRUE(S1.isDefined()) << "Symbol should be defined" ; |
340 | EXPECT_FALSE(S1.isExternal()) << "Symbol should not be external" ; |
341 | EXPECT_FALSE(S1.isAbsolute()) << "Symbol should not be absolute" ; |
342 | EXPECT_TRUE(&S1.getBlock()) << "Symbol should have a non-null block" ; |
343 | EXPECT_EQ(S1.getAddress(), orc::ExecutorAddr(0x1000)) |
344 | << "Unexpected symbol address" ; |
345 | |
346 | EXPECT_EQ( |
347 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 1U) |
348 | << "Unexpected number of defined symbols" ; |
349 | EXPECT_EQ( |
350 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
351 | 0U) |
352 | << "Unexpected number of external symbols" ; |
353 | |
354 | // Add an external symbol. |
355 | auto &S2 = G.addExternalSymbol(Name: "S2" , Size: 0, IsWeaklyReferenced: true); |
356 | |
357 | EXPECT_TRUE(S2.isExternal()) << "Symbol should be external" ; |
358 | EXPECT_EQ( |
359 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
360 | 1U) |
361 | << "Unexpected number of symbols" ; |
362 | |
363 | // Make S1 and S2 absolute, confirm that the its flags are updated and that it |
364 | // is moved from the defined/external symbols lists to the absolutes list. |
365 | orc::ExecutorAddr S1AbsAddr(0xA000); |
366 | orc::ExecutorAddr S2AbsAddr(0xB000); |
367 | G.makeAbsolute(Sym&: S1, Address: S1AbsAddr); |
368 | G.makeAbsolute(Sym&: S2, Address: S2AbsAddr); |
369 | |
370 | EXPECT_FALSE(S1.isDefined()) << "Symbol should not be defined" ; |
371 | EXPECT_FALSE(S1.isExternal()) << "Symbol should not be external" ; |
372 | EXPECT_TRUE(S1.isAbsolute()) << "Symbol should be absolute" ; |
373 | EXPECT_FALSE(S2.isDefined()) << "Symbol should not be defined" ; |
374 | EXPECT_FALSE(S2.isExternal()) << "Symbol should not be absolute" ; |
375 | EXPECT_TRUE(S2.isAbsolute()) << "Symbol should be absolute" ; |
376 | |
377 | EXPECT_EQ(S1.getAddress(), S1AbsAddr) << "Unexpected symbol address" ; |
378 | EXPECT_EQ(S2.getAddress(), S2AbsAddr) << "Unexpected symbol address" ; |
379 | |
380 | EXPECT_EQ( |
381 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 0U) |
382 | << "Unexpected number of defined symbols" ; |
383 | EXPECT_EQ( |
384 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
385 | 0U) |
386 | << "Unexpected number of external symbols" ; |
387 | EXPECT_EQ( |
388 | std::distance(G.absolute_symbols().begin(), G.absolute_symbols().end()), |
389 | 2U) |
390 | << "Unexpected number of external symbols" ; |
391 | } |
392 | |
393 | TEST(LinkGraphTest, MakeDefined) { |
394 | // Check that we can make an external symbol defined. |
395 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
396 | getGenericEdgeKindName); |
397 | auto &Sec = |
398 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
399 | |
400 | // Create an initial block. |
401 | orc::ExecutorAddr B1Addr(0x1000); |
402 | auto &B1 = G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
403 | |
404 | // Add an external symbol. |
405 | auto &S1 = G.addExternalSymbol(Name: "S1" , Size: 4, IsWeaklyReferenced: true); |
406 | |
407 | EXPECT_FALSE(S1.isDefined()) << "Symbol should not be defined" ; |
408 | EXPECT_TRUE(S1.isExternal()) << "Symbol should be external" ; |
409 | EXPECT_FALSE(S1.isAbsolute()) << "Symbol should not be absolute" ; |
410 | EXPECT_EQ(S1.getAddress(), orc::ExecutorAddr()) |
411 | << "Unexpected symbol address" ; |
412 | |
413 | EXPECT_EQ( |
414 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 0U) |
415 | << "Unexpected number of defined symbols" ; |
416 | EXPECT_EQ( |
417 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
418 | 1U) |
419 | << "Unexpected number of external symbols" ; |
420 | |
421 | // Make S1 defined, confirm that its flags are updated and that it is |
422 | // moved from the defined symbols to the externals list. |
423 | G.makeDefined(Sym&: S1, Content&: B1, Offset: 0, Size: 4, L: Linkage::Strong, S: Scope::Default, IsLive: false); |
424 | |
425 | EXPECT_TRUE(S1.isDefined()) << "Symbol should be defined" ; |
426 | EXPECT_FALSE(S1.isExternal()) << "Symbol should not be external" ; |
427 | EXPECT_FALSE(S1.isAbsolute()) << "Symbol should not be absolute" ; |
428 | EXPECT_TRUE(&S1.getBlock()) << "Symbol should have a non-null block" ; |
429 | EXPECT_EQ(S1.getAddress(), orc::ExecutorAddr(0x1000U)) |
430 | << "Unexpected symbol address" ; |
431 | |
432 | EXPECT_EQ( |
433 | std::distance(G.defined_symbols().begin(), G.defined_symbols().end()), 1U) |
434 | << "Unexpected number of defined symbols" ; |
435 | EXPECT_EQ( |
436 | std::distance(G.external_symbols().begin(), G.external_symbols().end()), |
437 | 0U) |
438 | << "Unexpected number of external symbols" ; |
439 | } |
440 | |
441 | TEST(LinkGraphTest, TransferDefinedSymbol) { |
442 | // Check that we can transfer a defined symbol from one block to another. |
443 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
444 | getGenericEdgeKindName); |
445 | auto &Sec = |
446 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
447 | |
448 | // Create initial blocks. |
449 | orc::ExecutorAddr B1Addr(0x1000); |
450 | auto &B1 = G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
451 | orc::ExecutorAddr B2Addr(0x2000); |
452 | auto &B2 = G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: B2Addr, Alignment: 8, AlignmentOffset: 0); |
453 | orc::ExecutorAddr B3Addr(0x3000); |
454 | auto &B3 = G.createContentBlock(Parent&: Sec, Content: BlockContent.slice(N: 0, M: 32), Address: B3Addr, Alignment: 8, AlignmentOffset: 0); |
455 | |
456 | // Add a symbol. |
457 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: B1.getSize(), L: Linkage::Strong, |
458 | S: Scope::Default, IsCallable: false, IsLive: false); |
459 | |
460 | // Transfer with zero offset, explicit size. |
461 | G.transferDefinedSymbol(Sym&: S1, DestBlock&: B2, NewOffset: 0, ExplicitNewSize: 64); |
462 | |
463 | EXPECT_EQ(&S1.getBlock(), &B2) << "Block was not updated" ; |
464 | EXPECT_EQ(S1.getOffset(), 0U) << "Unexpected offset" ; |
465 | EXPECT_EQ(S1.getSize(), 64U) << "Size was not updated" ; |
466 | |
467 | // Transfer with non-zero offset, implicit truncation. |
468 | G.transferDefinedSymbol(Sym&: S1, DestBlock&: B3, NewOffset: 16, ExplicitNewSize: std::nullopt); |
469 | |
470 | EXPECT_EQ(&S1.getBlock(), &B3) << "Block was not updated" ; |
471 | EXPECT_EQ(S1.getOffset(), 16U) << "Offset was not updated" ; |
472 | EXPECT_EQ(S1.getSize(), 16U) << "Size was not updated" ; |
473 | } |
474 | |
475 | TEST(LinkGraphTest, TransferDefinedSymbolAcrossSections) { |
476 | // Check that we can transfer a defined symbol from an existing block in one |
477 | // section to another. |
478 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
479 | getGenericEdgeKindName); |
480 | auto &Sec1 = |
481 | G.createSection(Name: "__data.1" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
482 | auto &Sec2 = |
483 | G.createSection(Name: "__data.2" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
484 | |
485 | // Create blocks in each section. |
486 | orc::ExecutorAddr B1Addr(0x1000); |
487 | auto &B1 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
488 | orc::ExecutorAddr B2Addr(0x2000); |
489 | auto &B2 = G.createContentBlock(Parent&: Sec2, Content: BlockContent, Address: B2Addr, Alignment: 8, AlignmentOffset: 0); |
490 | |
491 | // Add a symbol to section 1. |
492 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: B1.getSize(), L: Linkage::Strong, |
493 | S: Scope::Default, IsCallable: false, IsLive: false); |
494 | |
495 | // Transfer with zero offset, explicit size to section 2. |
496 | G.transferDefinedSymbol(Sym&: S1, DestBlock&: B2, NewOffset: 0, ExplicitNewSize: 64); |
497 | |
498 | EXPECT_EQ(&S1.getBlock(), &B2) << "Block was not updated" ; |
499 | EXPECT_EQ(S1.getOffset(), 0U) << "Unexpected offset" ; |
500 | EXPECT_EQ(S1.getSize(), 64U) << "Size was not updated" ; |
501 | |
502 | EXPECT_EQ(Sec1.symbols_size(), 0u) << "Symbol was not removed from Sec1" ; |
503 | EXPECT_EQ(Sec2.symbols_size(), 1u) << "Symbol was not added to Sec2" ; |
504 | if (Sec2.symbols_size() == 1) { |
505 | EXPECT_EQ(*Sec2.symbols().begin(), &S1) << "Unexpected symbol" ; |
506 | } |
507 | } |
508 | |
509 | TEST(LinkGraphTest, TransferBlock) { |
510 | // Check that we can transfer a block (and all associated symbols) from one |
511 | // section to another. |
512 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
513 | getGenericEdgeKindName); |
514 | auto &Sec1 = |
515 | G.createSection(Name: "__data.1" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
516 | auto &Sec2 = |
517 | G.createSection(Name: "__data.2" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
518 | |
519 | // Create an initial block. |
520 | orc::ExecutorAddr B1Addr(0x1000); |
521 | auto &B1 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
522 | orc::ExecutorAddr B2Addr(0x2000); |
523 | auto &B2 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B2Addr, Alignment: 8, AlignmentOffset: 0); |
524 | |
525 | // Add some symbols on B1... |
526 | G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: B1.getSize(), L: Linkage::Strong, S: Scope::Default, |
527 | IsCallable: false, IsLive: false); |
528 | G.addDefinedSymbol(Content&: B1, Offset: 1, Name: "S2" , Size: B1.getSize() - 1, L: Linkage::Strong, |
529 | S: Scope::Default, IsCallable: false, IsLive: false); |
530 | |
531 | // ... and on B2. |
532 | G.addDefinedSymbol(Content&: B2, Offset: 0, Name: "S3" , Size: B2.getSize(), L: Linkage::Strong, S: Scope::Default, |
533 | IsCallable: false, IsLive: false); |
534 | G.addDefinedSymbol(Content&: B2, Offset: 1, Name: "S4" , Size: B2.getSize() - 1, L: Linkage::Strong, |
535 | S: Scope::Default, IsCallable: false, IsLive: false); |
536 | |
537 | EXPECT_EQ(Sec1.blocks_size(), 2U) << "Expected two blocks in Sec1 initially" ; |
538 | EXPECT_EQ(Sec1.symbols_size(), 4U) |
539 | << "Expected four symbols in Sec1 initially" ; |
540 | EXPECT_EQ(Sec2.blocks_size(), 0U) << "Expected zero blocks in Sec2 initially" ; |
541 | EXPECT_EQ(Sec2.symbols_size(), 0U) |
542 | << "Expected zero symbols in Sec2 initially" ; |
543 | |
544 | // Transfer with zero offset, explicit size. |
545 | G.transferBlock(B&: B1, NewSection&: Sec2); |
546 | |
547 | EXPECT_EQ(Sec1.blocks_size(), 1U) |
548 | << "Expected one blocks in Sec1 after transfer" ; |
549 | EXPECT_EQ(Sec1.symbols_size(), 2U) |
550 | << "Expected two symbols in Sec1 after transfer" ; |
551 | EXPECT_EQ(Sec2.blocks_size(), 1U) |
552 | << "Expected one blocks in Sec2 after transfer" ; |
553 | EXPECT_EQ(Sec2.symbols_size(), 2U) |
554 | << "Expected two symbols in Sec2 after transfer" ; |
555 | } |
556 | |
557 | TEST(LinkGraphTest, MergeSections) { |
558 | // Check that we can transfer a block (and all associated symbols) from one |
559 | // section to another. |
560 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
561 | getGenericEdgeKindName); |
562 | auto &Sec1 = |
563 | G.createSection(Name: "__data.1" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
564 | auto &Sec2 = |
565 | G.createSection(Name: "__data.2" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
566 | auto &Sec3 = |
567 | G.createSection(Name: "__data.3" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
568 | |
569 | // Create an initial block. |
570 | orc::ExecutorAddr B1Addr(0x1000); |
571 | auto &B1 = G.createContentBlock(Parent&: Sec1, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
572 | orc::ExecutorAddr B2Addr(0x2000); |
573 | auto &B2 = G.createContentBlock(Parent&: Sec2, Content: BlockContent, Address: B2Addr, Alignment: 8, AlignmentOffset: 0); |
574 | orc::ExecutorAddr B3Addr(0x3000); |
575 | auto &B3 = G.createContentBlock(Parent&: Sec3, Content: BlockContent, Address: B3Addr, Alignment: 8, AlignmentOffset: 0); |
576 | |
577 | // Add a symbols for each block. |
578 | G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: B1.getSize(), L: Linkage::Strong, S: Scope::Default, |
579 | IsCallable: false, IsLive: false); |
580 | G.addDefinedSymbol(Content&: B2, Offset: 0, Name: "S2" , Size: B2.getSize(), L: Linkage::Strong, S: Scope::Default, |
581 | IsCallable: false, IsLive: false); |
582 | G.addDefinedSymbol(Content&: B3, Offset: 0, Name: "S3" , Size: B2.getSize(), L: Linkage::Strong, S: Scope::Default, |
583 | IsCallable: false, IsLive: false); |
584 | |
585 | EXPECT_EQ(&B1.getSection(), &Sec1); |
586 | EXPECT_EQ(&B2.getSection(), &Sec2); |
587 | EXPECT_EQ(G.sections_size(), 3U) << "Expected three sections initially" ; |
588 | EXPECT_EQ(Sec1.blocks_size(), 1U) << "Expected one block in Sec1 initially" ; |
589 | EXPECT_EQ(Sec1.symbols_size(), 1U) << "Expected one symbol in Sec1 initially" ; |
590 | EXPECT_EQ(Sec2.blocks_size(), 1U) << "Expected one block in Sec2 initially" ; |
591 | EXPECT_EQ(Sec2.symbols_size(), 1U) << "Expected one symbol in Sec2 initially" ; |
592 | EXPECT_EQ(Sec3.blocks_size(), 1U) << "Expected one block in Sec3 initially" ; |
593 | EXPECT_EQ(Sec3.symbols_size(), 1U) << "Expected one symbol in Sec3 initially" ; |
594 | |
595 | // Check that self-merge is a no-op. |
596 | G.mergeSections(DstSection&: Sec1, SrcSection&: Sec1); |
597 | |
598 | EXPECT_EQ(&B1.getSection(), &Sec1) |
599 | << "Expected B1.getSection() to remain unchanged" ; |
600 | EXPECT_EQ(G.sections_size(), 3U) |
601 | << "Expected three sections after first merge" ; |
602 | EXPECT_EQ(Sec1.blocks_size(), 1U) |
603 | << "Expected one block in Sec1 after first merge" ; |
604 | EXPECT_EQ(Sec1.symbols_size(), 1U) |
605 | << "Expected one symbol in Sec1 after first merge" ; |
606 | EXPECT_EQ(Sec2.blocks_size(), 1U) |
607 | << "Expected one block in Sec2 after first merge" ; |
608 | EXPECT_EQ(Sec2.symbols_size(), 1U) |
609 | << "Expected one symbol in Sec2 after first merge" ; |
610 | EXPECT_EQ(Sec3.blocks_size(), 1U) |
611 | << "Expected one block in Sec3 after first merge" ; |
612 | EXPECT_EQ(Sec3.symbols_size(), 1U) |
613 | << "Expected one symbol in Sec3 after first merge" ; |
614 | |
615 | // Merge Sec2 into Sec1, removing Sec2. |
616 | G.mergeSections(DstSection&: Sec1, SrcSection&: Sec2); |
617 | |
618 | EXPECT_EQ(&B2.getSection(), &Sec1) |
619 | << "Expected B2.getSection() to have been changed to &Sec1" ; |
620 | EXPECT_EQ(G.sections_size(), 2U) |
621 | << "Expected two sections after section merge" ; |
622 | EXPECT_EQ(Sec1.blocks_size(), 2U) |
623 | << "Expected two blocks in Sec1 after section merge" ; |
624 | EXPECT_EQ(Sec1.symbols_size(), 2U) |
625 | << "Expected two symbols in Sec1 after section merge" ; |
626 | EXPECT_EQ(Sec3.blocks_size(), 1U) |
627 | << "Expected one block in Sec3 after section merge" ; |
628 | EXPECT_EQ(Sec3.symbols_size(), 1U) |
629 | << "Expected one symbol in Sec3 after section merge" ; |
630 | |
631 | G.mergeSections(DstSection&: Sec1, SrcSection&: Sec3, PreserveSrcSection: true); |
632 | |
633 | EXPECT_EQ(G.sections_size(), 2U) << "Expected two sections after third merge" ; |
634 | EXPECT_EQ(Sec1.blocks_size(), 3U) |
635 | << "Expected three blocks in Sec1 after third merge" ; |
636 | EXPECT_EQ(Sec1.symbols_size(), 3U) |
637 | << "Expected three symbols in Sec1 after third merge" ; |
638 | EXPECT_EQ(Sec3.blocks_size(), 0U) |
639 | << "Expected one block in Sec3 after third merge" ; |
640 | EXPECT_EQ(Sec3.symbols_size(), 0U) |
641 | << "Expected one symbol in Sec3 after third merge" ; |
642 | } |
643 | |
644 | TEST(LinkGraphTest, SplitBlock) { |
645 | // Check that the LinkGraph::splitBlock test works as expected. |
646 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
647 | getGenericEdgeKindName); |
648 | auto &Sec = |
649 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
650 | |
651 | // Create the block to split. |
652 | orc::ExecutorAddr B1Addr(0x1000); |
653 | auto &B1 = G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: B1Addr, Alignment: 8, AlignmentOffset: 0); |
654 | |
655 | // Add some symbols to the block. |
656 | auto &S1 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S1" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
657 | IsCallable: false, IsLive: false); |
658 | auto &S2 = G.addDefinedSymbol(Content&: B1, Offset: 4, Name: "S2" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
659 | IsCallable: false, IsLive: false); |
660 | auto &S3 = G.addDefinedSymbol(Content&: B1, Offset: 8, Name: "S3" , Size: 4, L: Linkage::Strong, S: Scope::Default, |
661 | IsCallable: false, IsLive: false); |
662 | auto &S4 = G.addDefinedSymbol(Content&: B1, Offset: 12, Name: "S4" , Size: 4, L: Linkage::Strong, |
663 | S: Scope::Default, IsCallable: false, IsLive: false); |
664 | // Add a symbol that extends beyond the split. |
665 | auto &S5 = G.addDefinedSymbol(Content&: B1, Offset: 0, Name: "S5" , Size: 16, L: Linkage::Strong, |
666 | S: Scope::Default, IsCallable: false, IsLive: false); |
667 | |
668 | // Add an extra block, EB, and target symbols, and use these to add edges |
669 | // from B1 to EB. |
670 | orc::ExecutorAddr EBAddr(0x2000); |
671 | auto &EB = G.createContentBlock(Parent&: Sec, Content: BlockContent, Address: EBAddr, Alignment: 8, AlignmentOffset: 0); |
672 | auto &ES1 = G.addDefinedSymbol(Content&: EB, Offset: 0, Name: "TS1" , Size: 4, L: Linkage::Strong, |
673 | S: Scope::Default, IsCallable: false, IsLive: false); |
674 | auto &ES2 = G.addDefinedSymbol(Content&: EB, Offset: 4, Name: "TS2" , Size: 4, L: Linkage::Strong, |
675 | S: Scope::Default, IsCallable: false, IsLive: false); |
676 | auto &ES3 = G.addDefinedSymbol(Content&: EB, Offset: 8, Name: "TS3" , Size: 4, L: Linkage::Strong, |
677 | S: Scope::Default, IsCallable: false, IsLive: false); |
678 | auto &ES4 = G.addDefinedSymbol(Content&: EB, Offset: 12, Name: "TS4" , Size: 4, L: Linkage::Strong, |
679 | S: Scope::Default, IsCallable: false, IsLive: false); |
680 | |
681 | // Add edges from B1 to EB. |
682 | B1.addEdge(K: Edge::FirstRelocation, Offset: 0, Target&: ES1, Addend: 0); |
683 | B1.addEdge(K: Edge::FirstRelocation, Offset: 4, Target&: ES2, Addend: 0); |
684 | B1.addEdge(K: Edge::FirstRelocation, Offset: 8, Target&: ES3, Addend: 0); |
685 | B1.addEdge(K: Edge::FirstRelocation, Offset: 12, Target&: ES4, Addend: 0); |
686 | |
687 | // Split B1. |
688 | auto &B2 = G.splitBlock(B&: B1, SplitIndex: 8); |
689 | |
690 | // Check that the block addresses and content matches what we would expect. |
691 | EXPECT_EQ(B1.getAddress(), B1Addr + 8); |
692 | EXPECT_EQ(B1.getContent(), BlockContent.slice(8)); |
693 | |
694 | EXPECT_EQ(B2.getAddress(), B1Addr); |
695 | EXPECT_EQ(B2.getContent(), BlockContent.slice(0, 8)); |
696 | |
697 | // Check that symbols in B1 were transferred as expected: |
698 | // We expect S1 and S2 to have been transferred to B2, and S3 and S4 to have |
699 | // remained attached to B1. Symbols S3 and S4 should have had their offsets |
700 | // slid to account for the change in address of B2. |
701 | EXPECT_EQ(&S1.getBlock(), &B2); |
702 | EXPECT_EQ(S1.getOffset(), 0U); |
703 | |
704 | EXPECT_EQ(&S2.getBlock(), &B2); |
705 | EXPECT_EQ(S2.getOffset(), 4U); |
706 | |
707 | EXPECT_EQ(&S3.getBlock(), &B1); |
708 | EXPECT_EQ(S3.getOffset(), 0U); |
709 | |
710 | EXPECT_EQ(&S4.getBlock(), &B1); |
711 | EXPECT_EQ(S4.getOffset(), 4U); |
712 | |
713 | EXPECT_EQ(&S5.getBlock(), &B2); |
714 | EXPECT_EQ(S5.getOffset(), 0U); |
715 | // Size shrinks to fit. |
716 | EXPECT_EQ(S5.getSize(), 8U); |
717 | |
718 | // Check that edges in B1 have been transferred as expected: |
719 | // Both blocks should now have two edges each at offsets 0 and 4. |
720 | EXPECT_EQ(llvm::size(B1.edges()), 2); |
721 | if (size(Range: B1.edges()) == 2) { |
722 | auto *E1 = &*B1.edges().begin(); |
723 | auto *E2 = &*(B1.edges().begin() + 1); |
724 | if (E2->getOffset() < E1->getOffset()) |
725 | std::swap(a&: E1, b&: E2); |
726 | EXPECT_EQ(E1->getOffset(), 0U); |
727 | EXPECT_EQ(E2->getOffset(), 4U); |
728 | } |
729 | |
730 | EXPECT_EQ(llvm::size(B2.edges()), 2); |
731 | if (size(Range: B2.edges()) == 2) { |
732 | auto *E1 = &*B2.edges().begin(); |
733 | auto *E2 = &*(B2.edges().begin() + 1); |
734 | if (E2->getOffset() < E1->getOffset()) |
735 | std::swap(a&: E1, b&: E2); |
736 | EXPECT_EQ(E1->getOffset(), 0U); |
737 | EXPECT_EQ(E2->getOffset(), 4U); |
738 | } |
739 | } |
740 | |
741 | TEST(LinkGraphTest, GraphAllocationMethods) { |
742 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
743 | getGenericEdgeKindName); |
744 | |
745 | // Test allocation of sized, uninitialized buffer. |
746 | auto Buf1 = G.allocateBuffer(Size: 10); |
747 | EXPECT_EQ(Buf1.size(), 10U); |
748 | |
749 | // Test allocation of content-backed buffer. |
750 | char Buf2Src[] = {1, static_cast<char>(-1), 0, 42}; |
751 | auto Buf2 = G.allocateContent(Source: ArrayRef<char>(Buf2Src)); |
752 | EXPECT_EQ(Buf2, ArrayRef<char>(Buf2Src)); |
753 | |
754 | // Test c-string allocation from StringRef. |
755 | StringRef Buf3Src = "hello" ; |
756 | auto Buf3 = G.allocateCString(Source: Buf3Src); |
757 | EXPECT_TRUE(llvm::equal(Buf3.drop_back(1), Buf3Src)); |
758 | EXPECT_EQ(Buf3.back(), '\0'); |
759 | } |
760 | |
761 | TEST(LinkGraphTest, IsCStringBlockTest) { |
762 | // Check that the LinkGraph::splitBlock test works as expected. |
763 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
764 | getGenericEdgeKindName); |
765 | auto &Sec = |
766 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
767 | |
768 | char CString[] = "hello, world!" ; |
769 | char NotACString[] = {0, 1, 0, 1, 0}; |
770 | |
771 | auto &CStringBlock = |
772 | G.createContentBlock(Parent&: Sec, Content: CString, Address: orc::ExecutorAddr(), Alignment: 1, AlignmentOffset: 0); |
773 | auto &NotACStringBlock = |
774 | G.createContentBlock(Parent&: Sec, Content: NotACString, Address: orc::ExecutorAddr(), Alignment: 1, AlignmentOffset: 0); |
775 | auto &SizeOneZeroFillBlock = |
776 | G.createZeroFillBlock(Parent&: Sec, Size: 1, Address: orc::ExecutorAddr(), Alignment: 1, AlignmentOffset: 0); |
777 | auto &LargerZeroFillBlock = |
778 | G.createZeroFillBlock(Parent&: Sec, Size: 2, Address: orc::ExecutorAddr(), Alignment: 1, AlignmentOffset: 0); |
779 | |
780 | EXPECT_TRUE(isCStringBlock(CStringBlock)); |
781 | EXPECT_FALSE(isCStringBlock(NotACStringBlock)); |
782 | EXPECT_TRUE(isCStringBlock(SizeOneZeroFillBlock)); |
783 | EXPECT_FALSE(isCStringBlock(LargerZeroFillBlock)); |
784 | } |
785 | |
786 | TEST(LinkGraphTest, BasicLayoutHonorsNoAlloc) { |
787 | // Check that BasicLayout honors NoAlloc. |
788 | LinkGraph G("foo" , Triple("x86_64-apple-darwin" ), 8, llvm::endianness::little, |
789 | getGenericEdgeKindName); |
790 | |
791 | // Create a regular section and block. |
792 | auto &Sec1 = |
793 | G.createSection(Name: "__data" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
794 | G.createContentBlock(Parent&: Sec1, Content: BlockContent.slice(N: 0, M: 8), Address: orc::ExecutorAddr(), Alignment: 8, |
795 | AlignmentOffset: 0); |
796 | |
797 | // Create a NoAlloc section and block. |
798 | auto &Sec2 = |
799 | G.createSection(Name: "__metadata" , Prot: orc::MemProt::Read | orc::MemProt::Write); |
800 | Sec2.setMemLifetime(orc::MemLifetime::NoAlloc); |
801 | G.createContentBlock(Parent&: Sec2, Content: BlockContent.slice(N: 0, M: 8), Address: orc::ExecutorAddr(), Alignment: 8, |
802 | AlignmentOffset: 0); |
803 | |
804 | BasicLayout BL(G); |
805 | |
806 | EXPECT_EQ(std::distance(BL.segments().begin(), BL.segments().end()), 1U); |
807 | EXPECT_EQ(BL.segments().begin()->first, |
808 | orc::MemProt::Read | orc::MemProt::Write); |
809 | auto &SegInfo = BL.segments().begin()->second; |
810 | EXPECT_EQ(SegInfo.Alignment, 8U); |
811 | EXPECT_EQ(SegInfo.ContentSize, 8U); |
812 | } |
813 | |