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