1 //===-------- ObjectLinkingLayerTest.cpp - ObjectLinkingLayer tests -------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
10 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
11 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
12 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
13 #include "llvm/ExecutionEngine/JITSymbol.h"
14 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
15 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
16 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
17 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
18 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
19 #include "llvm/Testing/Support/Error.h"
20 #include "gtest/gtest.h"
23 using namespace llvm::jitlink
;
24 using namespace llvm::orc
;
28 const char BlockContentBytes
[] = {0x01, 0x02, 0x03, 0x04,
29 0x05, 0x06, 0x07, 0x08};
31 ArrayRef
<char> BlockContent(BlockContentBytes
);
33 class ObjectLinkingLayerTest
: public testing::Test
{
35 ~ObjectLinkingLayerTest() {
36 if (auto Err
= ES
.endSession())
37 ES
.reportError(std::move(Err
));
41 ExecutionSession ES
{std::make_unique
<UnsupportedExecutorProcessControl
>()};
42 JITDylib
&JD
= ES
.createBareJITDylib("main");
43 ObjectLinkingLayer ObjLinkingLayer
{
44 ES
, std::make_unique
<InProcessMemoryManager
>(4096)};
47 TEST_F(ObjectLinkingLayerTest
, AddLinkGraph
) {
48 auto G
= std::make_unique
<LinkGraph
>(
49 "foo", ES
.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
50 llvm::endianness::little
, x86_64::getEdgeKindName
);
52 auto &Sec1
= G
->createSection("__data", MemProt::Read
| MemProt::Write
);
53 auto &B1
= G
->createContentBlock(Sec1
, BlockContent
,
54 orc::ExecutorAddr(0x1000), 8, 0);
55 G
->addDefinedSymbol(B1
, 4, "_X", 4, Linkage::Strong
, Scope::Default
, false,
57 G
->addDefinedSymbol(B1
, 4, "_Y", 4, Linkage::Weak
, Scope::Default
, false,
59 G
->addDefinedSymbol(B1
, 4, "_Z", 4, Linkage::Strong
, Scope::Hidden
, false,
61 G
->addDefinedSymbol(B1
, 4, "_W", 4, Linkage::Strong
, Scope::Default
, true,
64 EXPECT_THAT_ERROR(ObjLinkingLayer
.add(JD
, std::move(G
)), Succeeded());
66 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, "_X"), Succeeded());
69 TEST_F(ObjectLinkingLayerTest
, ResourceTracker
) {
70 // This test transfers allocations to previously unknown ResourceTrackers,
71 // while increasing the number of trackers in the ObjectLinkingLayer, which
72 // may invalidate some iterators internally.
73 std::vector
<ResourceTrackerSP
> Trackers
;
74 for (unsigned I
= 0; I
< 64; I
++) {
75 auto G
= std::make_unique
<LinkGraph
>(
76 "foo", ES
.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
77 llvm::endianness::little
, x86_64::getEdgeKindName
);
79 auto &Sec1
= G
->createSection("__data", MemProt::Read
| MemProt::Write
);
80 auto &B1
= G
->createContentBlock(Sec1
, BlockContent
,
81 orc::ExecutorAddr(0x1000), 8, 0);
82 llvm::SmallString
<0> SymbolName
;
84 SymbolName
+= std::to_string(I
);
85 G
->addDefinedSymbol(B1
, 4, SymbolName
, 4, Linkage::Strong
, Scope::Default
,
88 auto RT1
= JD
.createResourceTracker();
89 EXPECT_THAT_ERROR(ObjLinkingLayer
.add(RT1
, std::move(G
)), Succeeded());
90 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, SymbolName
), Succeeded());
92 auto RT2
= JD
.createResourceTracker();
93 RT1
->transferTo(*RT2
);
95 Trackers
.push_back(RT2
);
99 TEST_F(ObjectLinkingLayerTest
, ClaimLateDefinedWeakSymbols
) {
100 // Check that claiming weak symbols works as expected.
102 // To do this we'll need a custom plugin to inject some new symbols during
104 class TestPlugin
: public ObjectLinkingLayer::Plugin
{
106 void modifyPassConfig(MaterializationResponsibility
&MR
,
107 jitlink::LinkGraph
&G
,
108 jitlink::PassConfiguration
&Config
) override
{
109 Config
.PrePrunePasses
.insert(
110 Config
.PrePrunePasses
.begin(), [](LinkGraph
&G
) {
111 auto *DataSec
= G
.findSectionByName("__data");
112 auto &DataBlock
= G
.createContentBlock(
113 *DataSec
, BlockContent
, orc::ExecutorAddr(0x2000), 8, 0);
114 G
.addDefinedSymbol(DataBlock
, 4, "_x", 4, Linkage::Weak
,
115 Scope::Default
, false, false);
118 G
.createSection("__text", MemProt::Read
| MemProt::Write
);
119 auto &FuncBlock
= G
.createContentBlock(
120 TextSec
, BlockContent
, orc::ExecutorAddr(0x3000), 8, 0);
121 G
.addDefinedSymbol(FuncBlock
, 4, "_f", 4, Linkage::Weak
,
122 Scope::Default
, true, false);
124 return Error::success();
128 Error
notifyFailed(MaterializationResponsibility
&MR
) override
{
129 llvm_unreachable("unexpected error");
132 Error
notifyRemovingResources(JITDylib
&JD
, ResourceKey K
) override
{
133 return Error::success();
135 void notifyTransferringResources(JITDylib
&JD
, ResourceKey DstKey
,
136 ResourceKey SrcKey
) override
{
137 llvm_unreachable("unexpected resource transfer");
141 ObjLinkingLayer
.addPlugin(std::make_unique
<TestPlugin
>());
142 auto G
= std::make_unique
<LinkGraph
>(
143 "foo", ES
.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
144 llvm::endianness::little
, getGenericEdgeKindName
);
146 auto &DataSec
= G
->createSection("__data", MemProt::Read
| MemProt::Write
);
147 auto &DataBlock
= G
->createContentBlock(DataSec
, BlockContent
,
148 orc::ExecutorAddr(0x1000), 8, 0);
149 G
->addDefinedSymbol(DataBlock
, 4, "_anchor", 4, Linkage::Weak
, Scope::Default
,
152 EXPECT_THAT_ERROR(ObjLinkingLayer
.add(JD
, std::move(G
)), Succeeded());
154 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, "_anchor"), Succeeded());
157 TEST_F(ObjectLinkingLayerTest
, HandleErrorDuringPostAllocationPass
) {
158 // We want to confirm that Errors in post allocation passes correctly
159 // abandon the in-flight allocation and report an error.
160 class TestPlugin
: public ObjectLinkingLayer::Plugin
{
162 ~TestPlugin() { EXPECT_TRUE(ErrorReported
); }
164 void modifyPassConfig(MaterializationResponsibility
&MR
,
165 jitlink::LinkGraph
&G
,
166 jitlink::PassConfiguration
&Config
) override
{
167 Config
.PostAllocationPasses
.insert(
168 Config
.PostAllocationPasses
.begin(), [](LinkGraph
&G
) {
169 return make_error
<StringError
>("Kaboom", inconvertibleErrorCode());
173 Error
notifyFailed(MaterializationResponsibility
&MR
) override
{
174 ErrorReported
= true;
175 return Error::success();
178 Error
notifyRemovingResources(JITDylib
&JD
, ResourceKey K
) override
{
179 return Error::success();
181 void notifyTransferringResources(JITDylib
&JD
, ResourceKey DstKey
,
182 ResourceKey SrcKey
) override
{
183 llvm_unreachable("unexpected resource transfer");
187 bool ErrorReported
= false;
190 // We expect this test to generate errors. Consume them so that we don't
191 // add noise to the test logs.
192 ES
.setErrorReporter(consumeError
);
194 ObjLinkingLayer
.addPlugin(std::make_unique
<TestPlugin
>());
195 auto G
= std::make_unique
<LinkGraph
>(
196 "foo", ES
.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
197 llvm::endianness::little
, getGenericEdgeKindName
);
199 auto &DataSec
= G
->createSection("__data", MemProt::Read
| MemProt::Write
);
200 auto &DataBlock
= G
->createContentBlock(DataSec
, BlockContent
,
201 orc::ExecutorAddr(0x1000), 8, 0);
202 G
->addDefinedSymbol(DataBlock
, 4, "_anchor", 4, Linkage::Weak
, Scope::Default
,
205 EXPECT_THAT_ERROR(ObjLinkingLayer
.add(JD
, std::move(G
)), Succeeded());
207 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, "_anchor"), Failed());
210 TEST_F(ObjectLinkingLayerTest
, AddAndRemovePlugins
) {
211 class TestPlugin
: public ObjectLinkingLayer::Plugin
{
213 TestPlugin(size_t &ActivationCount
, bool &PluginDestroyed
)
214 : ActivationCount(ActivationCount
), PluginDestroyed(PluginDestroyed
) {}
216 ~TestPlugin() { PluginDestroyed
= true; }
218 void modifyPassConfig(MaterializationResponsibility
&MR
,
219 jitlink::LinkGraph
&G
,
220 jitlink::PassConfiguration
&Config
) override
{
224 Error
notifyFailed(MaterializationResponsibility
&MR
) override
{
225 ADD_FAILURE() << "TestPlugin::notifyFailed called unexpectedly";
226 return Error::success();
229 Error
notifyRemovingResources(JITDylib
&JD
, ResourceKey K
) override
{
230 return Error::success();
233 void notifyTransferringResources(JITDylib
&JD
, ResourceKey DstKey
,
234 ResourceKey SrcKey
) override
{}
237 size_t &ActivationCount
;
238 bool &PluginDestroyed
;
241 size_t ActivationCount
= 0;
242 bool PluginDestroyed
= false;
244 auto P
= std::make_shared
<TestPlugin
>(ActivationCount
, PluginDestroyed
);
246 ObjLinkingLayer
.addPlugin(P
);
249 auto G1
= std::make_unique
<LinkGraph
>(
250 "G1", ES
.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
251 llvm::endianness::little
, x86_64::getEdgeKindName
);
253 auto &DataSec
= G1
->createSection("__data", MemProt::Read
| MemProt::Write
);
254 auto &DataBlock
= G1
->createContentBlock(DataSec
, BlockContent
,
255 orc::ExecutorAddr(0x1000), 8, 0);
256 G1
->addDefinedSymbol(DataBlock
, 4, "_anchor1", 4, Linkage::Weak
,
257 Scope::Default
, false, true);
259 EXPECT_THAT_ERROR(ObjLinkingLayer
.add(JD
, std::move(G1
)), Succeeded());
260 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, "_anchor1"), Succeeded());
261 EXPECT_EQ(ActivationCount
, 1U);
264 ObjLinkingLayer
.removePlugin(*P
);
267 auto G2
= std::make_unique
<LinkGraph
>(
268 "G2", ES
.getSymbolStringPool(), Triple("x86_64-apple-darwin"), 8,
269 llvm::endianness::little
, x86_64::getEdgeKindName
);
271 auto &DataSec
= G2
->createSection("__data", MemProt::Read
| MemProt::Write
);
272 auto &DataBlock
= G2
->createContentBlock(DataSec
, BlockContent
,
273 orc::ExecutorAddr(0x1000), 8, 0);
274 G2
->addDefinedSymbol(DataBlock
, 4, "_anchor2", 4, Linkage::Weak
,
275 Scope::Default
, false, true);
277 EXPECT_THAT_ERROR(ObjLinkingLayer
.add(JD
, std::move(G2
)), Succeeded());
278 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, "_anchor2"), Succeeded());
279 EXPECT_EQ(ActivationCount
, 1U);
283 EXPECT_TRUE(PluginDestroyed
);
286 TEST(ObjectLinkingLayerSearchGeneratorTest
, AbsoluteSymbolsObjectLayer
) {
287 class TestEPC
: public UnsupportedExecutorProcessControl
,
288 public DylibManager
{
291 : UnsupportedExecutorProcessControl(nullptr, nullptr,
292 "x86_64-apple-darwin") {
293 this->DylibMgr
= this;
296 Expected
<tpctypes::DylibHandle
> loadDylib(const char *DylibPath
) override
{
297 return ExecutorAddr::fromPtr((void *)nullptr);
300 void lookupSymbolsAsync(ArrayRef
<LookupRequest
> Request
,
301 SymbolLookupCompleteFn Complete
) override
{
302 std::vector
<ExecutorSymbolDef
> Result
;
303 EXPECT_EQ(Request
.size(), 1u);
304 for (auto &LR
: Request
) {
305 EXPECT_EQ(LR
.Symbols
.size(), 1u);
306 for (auto &Sym
: LR
.Symbols
) {
307 if (*Sym
.first
== "_testFunc") {
308 ExecutorSymbolDef Def
{ExecutorAddr::fromPtr((void *)0x1000),
309 JITSymbolFlags::Exported
};
310 Result
.push_back(Def
);
312 ADD_FAILURE() << "unexpected symbol request " << *Sym
.first
;
316 Complete(std::vector
<tpctypes::LookupResult
>{1, Result
});
320 ExecutionSession ES
{std::make_unique
<TestEPC
>()};
321 JITDylib
&JD
= ES
.createBareJITDylib("main");
322 ObjectLinkingLayer ObjLinkingLayer
{
323 ES
, std::make_unique
<InProcessMemoryManager
>(4096)};
325 auto G
= EPCDynamicLibrarySearchGenerator::GetForTargetProcess(
326 ES
, {}, [&](JITDylib
&JD
, SymbolMap Syms
) {
327 auto G
= absoluteSymbolsLinkGraph(
328 ES
.getTargetTriple(), ES
.getSymbolStringPool(), std::move(Syms
));
329 return ObjLinkingLayer
.add(JD
, std::move(G
));
331 ASSERT_THAT_EXPECTED(G
, Succeeded());
332 JD
.addGenerator(std::move(*G
));
334 class CheckDefs
: public ObjectLinkingLayer::Plugin
{
336 ~CheckDefs() { EXPECT_TRUE(SawSymbolDef
); }
338 void modifyPassConfig(MaterializationResponsibility
&MR
,
339 jitlink::LinkGraph
&G
,
340 jitlink::PassConfiguration
&Config
) override
{
341 Config
.PostAllocationPasses
.push_back([this](LinkGraph
&G
) {
342 unsigned SymCount
= 0;
343 for (Symbol
*Sym
: G
.absolute_symbols()) {
345 if (!Sym
->hasName()) {
346 ADD_FAILURE() << "unexpected unnamed symbol";
349 if (*Sym
->getName() == "_testFunc")
352 ADD_FAILURE() << "unexpected symbol " << Sym
->getName();
354 EXPECT_EQ(SymCount
, 1u);
355 return Error::success();
359 Error
notifyFailed(MaterializationResponsibility
&MR
) override
{
360 return Error::success();
363 Error
notifyRemovingResources(JITDylib
&JD
, ResourceKey K
) override
{
364 return Error::success();
366 void notifyTransferringResources(JITDylib
&JD
, ResourceKey DstKey
,
367 ResourceKey SrcKey
) override
{
368 llvm_unreachable("unexpected resource transfer");
372 bool SawSymbolDef
= false;
375 ObjLinkingLayer
.addPlugin(std::make_unique
<CheckDefs
>());
377 EXPECT_THAT_EXPECTED(ES
.lookup(&JD
, "_testFunc"), Succeeded());
378 EXPECT_THAT_ERROR(ES
.endSession(), Succeeded());
381 } // end anonymous namespace