1 //===- llvm-jitlink.cpp -- Command line interface/tester for llvm-jitlink -===// 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 // This utility provides a simple command line interface to the llvm jitlink 10 // library, which makes relocatable object files executable in memory. Its 11 // primary function is as a testing utility for the jitlink library. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm-jitlink.h" 16 17 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" 18 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 19 #include "llvm/MC/MCAsmInfo.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCDisassembler/MCDisassembler.h" 22 #include "llvm/MC/MCInstPrinter.h" 23 #include "llvm/MC/MCInstrInfo.h" 24 #include "llvm/MC/MCRegisterInfo.h" 25 #include "llvm/MC/MCSubtargetInfo.h" 26 #include "llvm/MC/MCTargetOptions.h" 27 #include "llvm/Object/COFF.h" 28 #include "llvm/Object/MachO.h" 29 #include "llvm/Object/ObjectFile.h" 30 #include "llvm/Support/CommandLine.h" 31 #include "llvm/Support/Debug.h" 32 #include "llvm/Support/DynamicLibrary.h" 33 #include "llvm/Support/InitLLVM.h" 34 #include "llvm/Support/MemoryBuffer.h" 35 #include "llvm/Support/Process.h" 36 #include "llvm/Support/TargetRegistry.h" 37 #include "llvm/Support/TargetSelect.h" 38 #include "llvm/Support/Timer.h" 39 40 #include <list> 41 #include <string> 42 43 #define DEBUG_TYPE "llvm-jitlink" 44 45 using namespace llvm; 46 using namespace llvm::jitlink; 47 using namespace llvm::orc; 48 49 static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore, 50 cl::desc("input files")); 51 52 static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"), 53 cl::init(false)); 54 55 static cl::list<std::string> 56 CheckFiles("check", cl::desc("File containing verifier checks"), 57 cl::ZeroOrMore); 58 59 static cl::opt<std::string> 60 EntryPointName("entry", cl::desc("Symbol to call as main entry point"), 61 cl::init("")); 62 63 static cl::list<std::string> JITLinkDylibs( 64 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent " 65 "input file arguments")); 66 67 static cl::list<std::string> 68 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"), 69 cl::ZeroOrMore); 70 71 static cl::list<std::string> InputArgv("args", cl::Positional, 72 cl::desc("<program arguments>..."), 73 cl::ZeroOrMore, cl::PositionalEatsArgs); 74 75 static cl::opt<bool> 76 NoProcessSymbols("no-process-syms", 77 cl::desc("Do not resolve to llvm-jitlink process symbols"), 78 cl::init(false)); 79 80 static cl::list<std::string> AbsoluteDefs( 81 "define-abs", 82 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"), 83 cl::ZeroOrMore); 84 85 static cl::opt<bool> ShowAddrs( 86 "show-addrs", 87 cl::desc("Print registered symbol, section, got and stub addresses"), 88 cl::init(false)); 89 90 static cl::opt<bool> ShowLinkGraph( 91 "show-graph", 92 cl::desc("Print the link graph after fixups have been applied"), 93 cl::init(false)); 94 95 static cl::opt<bool> ShowSizes( 96 "show-sizes", 97 cl::desc("Show sizes pre- and post-dead stripping, and allocations"), 98 cl::init(false)); 99 100 static cl::opt<bool> ShowTimes("show-times", 101 cl::desc("Show times for llvm-jitlink phases"), 102 cl::init(false)); 103 104 static cl::opt<std::string> SlabAllocateSizeString( 105 "slab-allocate", 106 cl::desc("Allocate from a slab of the given size " 107 "(allowable suffixes: Kb, Mb, Gb. default = " 108 "Kb)"), 109 cl::init("")); 110 111 static cl::opt<bool> ShowRelocatedSectionContents( 112 "show-relocated-section-contents", 113 cl::desc("show section contents after fixups have been applied"), 114 cl::init(false)); 115 116 ExitOnError ExitOnErr; 117 118 namespace llvm { 119 120 static raw_ostream & 121 operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) { 122 return OS << "target addr = " 123 << format("0x%016" PRIx64, MRI.getTargetAddress()) 124 << ", content: " << (const void *)MRI.getContent().data() << " -- " 125 << (const void *)(MRI.getContent().data() + MRI.getContent().size()) 126 << " (" << MRI.getContent().size() << " bytes)"; 127 } 128 129 static raw_ostream & 130 operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) { 131 OS << "Symbols:\n"; 132 for (auto &SKV : SIM) 133 OS << " \"" << SKV.first() << "\" " << SKV.second << "\n"; 134 return OS; 135 } 136 137 static raw_ostream & 138 operator<<(raw_ostream &OS, const Session::FileInfo &FI) { 139 for (auto &SIKV : FI.SectionInfos) 140 OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n"; 141 for (auto &GOTKV : FI.GOTEntryInfos) 142 OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n"; 143 for (auto &StubKV : FI.StubInfos) 144 OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n"; 145 return OS; 146 } 147 148 static raw_ostream & 149 operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) { 150 for (auto &FIKV : FIM) 151 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second; 152 return OS; 153 } 154 155 static uint64_t computeTotalBlockSizes(LinkGraph &G) { 156 uint64_t TotalSize = 0; 157 for (auto *B : G.blocks()) 158 TotalSize += B->getSize(); 159 return TotalSize; 160 } 161 162 static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) { 163 constexpr JITTargetAddress DumpWidth = 16; 164 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two"); 165 166 // Put sections in address order. 167 std::vector<Section *> Sections; 168 for (auto &S : G.sections()) 169 Sections.push_back(&S); 170 171 std::sort(Sections.begin(), Sections.end(), 172 [](const Section *LHS, const Section *RHS) { 173 if (LHS->symbols_empty() && RHS->symbols_empty()) 174 return false; 175 if (LHS->symbols_empty()) 176 return false; 177 if (RHS->symbols_empty()) 178 return true; 179 SectionRange LHSRange(*LHS); 180 SectionRange RHSRange(*RHS); 181 return LHSRange.getStart() < RHSRange.getStart(); 182 }); 183 184 for (auto *S : Sections) { 185 OS << S->getName() << " content:"; 186 if (S->symbols_empty()) { 187 OS << "\n section empty\n"; 188 continue; 189 } 190 191 // Sort symbols into order, then render. 192 std::vector<Symbol *> Syms(S->symbols().begin(), S->symbols().end()); 193 llvm::sort(Syms, [](const Symbol *LHS, const Symbol *RHS) { 194 return LHS->getAddress() < RHS->getAddress(); 195 }); 196 197 JITTargetAddress NextAddr = Syms.front()->getAddress() & ~(DumpWidth - 1); 198 for (auto *Sym : Syms) { 199 bool IsZeroFill = Sym->getBlock().isZeroFill(); 200 JITTargetAddress SymStart = Sym->getAddress(); 201 JITTargetAddress SymSize = Sym->getSize(); 202 JITTargetAddress SymEnd = SymStart + SymSize; 203 const uint8_t *SymData = 204 IsZeroFill ? nullptr : Sym->getSymbolContent().bytes_begin(); 205 206 // Pad any space before the symbol starts. 207 while (NextAddr != SymStart) { 208 if (NextAddr % DumpWidth == 0) 209 OS << formatv("\n{0:x16}:", NextAddr); 210 OS << " "; 211 ++NextAddr; 212 } 213 214 // Render the symbol content. 215 while (NextAddr != SymEnd) { 216 if (NextAddr % DumpWidth == 0) 217 OS << formatv("\n{0:x16}:", NextAddr); 218 if (IsZeroFill) 219 OS << " 00"; 220 else 221 OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]); 222 ++NextAddr; 223 } 224 } 225 OS << "\n"; 226 } 227 } 228 229 class JITLinkSlabAllocator final : public JITLinkMemoryManager { 230 public: 231 static Expected<std::unique_ptr<JITLinkSlabAllocator>> 232 Create(uint64_t SlabSize) { 233 Error Err = Error::success(); 234 std::unique_ptr<JITLinkSlabAllocator> Allocator( 235 new JITLinkSlabAllocator(SlabSize, Err)); 236 if (Err) 237 return std::move(Err); 238 return std::move(Allocator); 239 } 240 241 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>> 242 allocate(const SegmentsRequestMap &Request) override { 243 244 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>; 245 246 // Local class for allocation. 247 class IPMMAlloc : public Allocation { 248 public: 249 IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {} 250 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override { 251 assert(SegBlocks.count(Seg) && "No allocation for segment"); 252 return {static_cast<char *>(SegBlocks[Seg].base()), 253 SegBlocks[Seg].allocatedSize()}; 254 } 255 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override { 256 assert(SegBlocks.count(Seg) && "No allocation for segment"); 257 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base()); 258 } 259 void finalizeAsync(FinalizeContinuation OnFinalize) override { 260 OnFinalize(applyProtections()); 261 } 262 Error deallocate() override { 263 for (auto &KV : SegBlocks) 264 if (auto EC = sys::Memory::releaseMappedMemory(KV.second)) 265 return errorCodeToError(EC); 266 return Error::success(); 267 } 268 269 private: 270 Error applyProtections() { 271 for (auto &KV : SegBlocks) { 272 auto &Prot = KV.first; 273 auto &Block = KV.second; 274 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot)) 275 return errorCodeToError(EC); 276 if (Prot & sys::Memory::MF_EXEC) 277 sys::Memory::InvalidateInstructionCache(Block.base(), 278 Block.allocatedSize()); 279 } 280 return Error::success(); 281 } 282 283 AllocationMap SegBlocks; 284 }; 285 286 AllocationMap Blocks; 287 288 for (auto &KV : Request) { 289 auto &Seg = KV.second; 290 291 if (Seg.getAlignment() > PageSize) 292 return make_error<StringError>("Cannot request higher than page " 293 "alignment", 294 inconvertibleErrorCode()); 295 296 if (PageSize % Seg.getAlignment() != 0) 297 return make_error<StringError>("Page size is not a multiple of " 298 "alignment", 299 inconvertibleErrorCode()); 300 301 uint64_t ZeroFillStart = Seg.getContentSize(); 302 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize(); 303 304 // Round segment size up to page boundary. 305 SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1); 306 307 // Take segment bytes from the front of the slab. 308 void *SlabBase = SlabRemaining.base(); 309 uint64_t SlabRemainingSize = SlabRemaining.allocatedSize(); 310 311 if (SegmentSize > SlabRemainingSize) 312 return make_error<StringError>("Slab allocator out of memory", 313 inconvertibleErrorCode()); 314 315 sys::MemoryBlock SegMem(SlabBase, SegmentSize); 316 SlabRemaining = 317 sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize, 318 SlabRemainingSize - SegmentSize); 319 320 // Zero out the zero-fill memory. 321 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0, 322 Seg.getZeroFillSize()); 323 324 // Record the block for this segment. 325 Blocks[KV.first] = std::move(SegMem); 326 } 327 return std::unique_ptr<InProcessMemoryManager::Allocation>( 328 new IPMMAlloc(std::move(Blocks))); 329 } 330 331 private: 332 JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) { 333 ErrorAsOutParameter _(&Err); 334 335 PageSize = sys::Process::getPageSizeEstimate(); 336 337 if (!isPowerOf2_64(PageSize)) { 338 Err = make_error<StringError>("Page size is not a power of 2", 339 inconvertibleErrorCode()); 340 return; 341 } 342 343 // Round slab request up to page size. 344 SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1); 345 346 const sys::Memory::ProtectionFlags ReadWrite = 347 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 348 sys::Memory::MF_WRITE); 349 350 std::error_code EC; 351 SlabRemaining = 352 sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC); 353 354 if (EC) { 355 Err = errorCodeToError(EC); 356 return; 357 } 358 } 359 360 sys::MemoryBlock SlabRemaining; 361 uint64_t PageSize = 0; 362 }; 363 364 Expected<uint64_t> getSlabAllocSize(StringRef SizeString) { 365 SizeString = SizeString.trim(); 366 367 uint64_t Units = 1024; 368 369 if (SizeString.endswith_lower("kb")) 370 SizeString = SizeString.drop_back(2).rtrim(); 371 else if (SizeString.endswith_lower("mb")) { 372 Units = 1024 * 1024; 373 SizeString = SizeString.drop_back(2).rtrim(); 374 } else if (SizeString.endswith_lower("gb")) { 375 Units = 1024 * 1024 * 1024; 376 SizeString = SizeString.drop_back(2).rtrim(); 377 } 378 379 uint64_t SlabSize = 0; 380 if (SizeString.getAsInteger(10, SlabSize)) 381 return make_error<StringError>("Invalid numeric format for slab size", 382 inconvertibleErrorCode()); 383 384 return SlabSize * Units; 385 } 386 387 static std::unique_ptr<jitlink::JITLinkMemoryManager> createMemoryManager() { 388 if (!SlabAllocateSizeString.empty()) { 389 auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString)); 390 return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize)); 391 } 392 return std::make_unique<jitlink::InProcessMemoryManager>(); 393 } 394 395 Session::Session(Triple TT) 396 : MemMgr(createMemoryManager()), ObjLayer(ES, *MemMgr), TT(std::move(TT)) { 397 398 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the 399 /// Session. 400 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin { 401 public: 402 JITLinkSessionPlugin(Session &S) : S(S) {} 403 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, 404 PassConfiguration &PassConfig) { 405 S.modifyPassConfig(TT, PassConfig); 406 } 407 408 private: 409 Session &S; 410 }; 411 412 if (!NoExec && !TT.isOSWindows()) 413 ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>( 414 InProcessEHFrameRegistrar::getInstance())); 415 416 ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this)); 417 } 418 419 void Session::dumpSessionInfo(raw_ostream &OS) { 420 OS << "Registered addresses:\n" << SymbolInfos << FileInfos; 421 } 422 423 void Session::modifyPassConfig(const Triple &FTT, 424 PassConfiguration &PassConfig) { 425 if (!CheckFiles.empty()) 426 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) { 427 if (TT.getObjectFormat() == Triple::MachO) 428 return registerMachOStubsAndGOT(*this, G); 429 return make_error<StringError>("Unsupported object format for GOT/stub " 430 "registration", 431 inconvertibleErrorCode()); 432 }); 433 434 if (ShowLinkGraph) 435 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error { 436 outs() << "Link graph post-fixup:\n"; 437 G.dump(outs()); 438 return Error::success(); 439 }); 440 441 if (ShowSizes) { 442 PassConfig.PrePrunePasses.push_back([this](LinkGraph &G) -> Error { 443 SizeBeforePruning += computeTotalBlockSizes(G); 444 return Error::success(); 445 }); 446 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) -> Error { 447 SizeAfterFixups += computeTotalBlockSizes(G); 448 return Error::success(); 449 }); 450 } 451 452 if (ShowRelocatedSectionContents) 453 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error { 454 outs() << "Relocated section contents for " << G.getName() << ":\n"; 455 dumpSectionContents(outs(), G); 456 return Error::success(); 457 }); 458 } 459 460 Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) { 461 auto FileInfoItr = FileInfos.find(FileName); 462 if (FileInfoItr == FileInfos.end()) 463 return make_error<StringError>("file \"" + FileName + "\" not recognized", 464 inconvertibleErrorCode()); 465 return FileInfoItr->second; 466 } 467 468 Expected<Session::MemoryRegionInfo &> 469 Session::findSectionInfo(StringRef FileName, StringRef SectionName) { 470 auto FI = findFileInfo(FileName); 471 if (!FI) 472 return FI.takeError(); 473 auto SecInfoItr = FI->SectionInfos.find(SectionName); 474 if (SecInfoItr == FI->SectionInfos.end()) 475 return make_error<StringError>("no section \"" + SectionName + 476 "\" registered for file \"" + FileName + 477 "\"", 478 inconvertibleErrorCode()); 479 return SecInfoItr->second; 480 } 481 482 Expected<Session::MemoryRegionInfo &> 483 Session::findStubInfo(StringRef FileName, StringRef TargetName) { 484 auto FI = findFileInfo(FileName); 485 if (!FI) 486 return FI.takeError(); 487 auto StubInfoItr = FI->StubInfos.find(TargetName); 488 if (StubInfoItr == FI->StubInfos.end()) 489 return make_error<StringError>("no stub for \"" + TargetName + 490 "\" registered for file \"" + FileName + 491 "\"", 492 inconvertibleErrorCode()); 493 return StubInfoItr->second; 494 } 495 496 Expected<Session::MemoryRegionInfo &> 497 Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) { 498 auto FI = findFileInfo(FileName); 499 if (!FI) 500 return FI.takeError(); 501 auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName); 502 if (GOTInfoItr == FI->GOTEntryInfos.end()) 503 return make_error<StringError>("no GOT entry for \"" + TargetName + 504 "\" registered for file \"" + FileName + 505 "\"", 506 inconvertibleErrorCode()); 507 return GOTInfoItr->second; 508 } 509 510 bool Session::isSymbolRegistered(StringRef SymbolName) { 511 return SymbolInfos.count(SymbolName); 512 } 513 514 Expected<Session::MemoryRegionInfo &> 515 Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) { 516 auto SymInfoItr = SymbolInfos.find(SymbolName); 517 if (SymInfoItr == SymbolInfos.end()) 518 return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName + 519 " not found", 520 inconvertibleErrorCode()); 521 return SymInfoItr->second; 522 } 523 524 } // end namespace llvm 525 526 Triple getFirstFileTriple() { 527 assert(!InputFiles.empty() && "InputFiles can not be empty"); 528 auto ObjBuffer = 529 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front()))); 530 auto Obj = ExitOnErr( 531 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())); 532 return Obj->makeTriple(); 533 } 534 535 Error sanitizeArguments(const Session &S) { 536 if (EntryPointName.empty()) { 537 if (S.TT.getObjectFormat() == Triple::MachO) 538 EntryPointName = "_main"; 539 else 540 EntryPointName = "main"; 541 } 542 543 if (NoExec && !InputArgv.empty()) 544 outs() << "Warning: --args passed to -noexec run will be ignored.\n"; 545 546 return Error::success(); 547 } 548 549 Error loadProcessSymbols(Session &S) { 550 std::string ErrMsg; 551 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg)) 552 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); 553 554 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0'; 555 auto InternedEntryPointName = S.ES.intern(EntryPointName); 556 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) { 557 return Name != InternedEntryPointName; 558 }; 559 S.ES.getMainJITDylib().addGenerator( 560 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( 561 GlobalPrefix, FilterMainEntryPoint))); 562 563 return Error::success(); 564 } 565 566 Error loadDylibs() { 567 // FIXME: This should all be handled inside DynamicLibrary. 568 for (const auto &Dylib : Dylibs) { 569 if (!sys::fs::is_regular_file(Dylib)) 570 return make_error<StringError>("\"" + Dylib + "\" is not a regular file", 571 inconvertibleErrorCode()); 572 std::string ErrMsg; 573 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg)) 574 return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); 575 } 576 577 return Error::success(); 578 } 579 580 Error loadObjects(Session &S) { 581 582 std::map<unsigned, JITDylib *> IdxToJLD; 583 584 // First, set up JITDylibs. 585 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n"); 586 { 587 // Create a "main" JITLinkDylib. 588 auto &MainJD = S.ES.getMainJITDylib(); 589 IdxToJLD[0] = &MainJD; 590 S.JDSearchOrder.push_back(&MainJD); 591 LLVM_DEBUG(dbgs() << " 0: " << MainJD.getName() << "\n"); 592 593 // Add any extra JITLinkDylibs from the command line. 594 std::string JDNamePrefix("lib"); 595 for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end(); 596 JLDItr != JLDEnd; ++JLDItr) { 597 auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr); 598 unsigned JDIdx = 599 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin()); 600 IdxToJLD[JDIdx] = &JD; 601 S.JDSearchOrder.push_back(&JD); 602 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n"); 603 } 604 605 // Set every dylib to link against every other, in command line order. 606 for (auto *JD : S.JDSearchOrder) { 607 JITDylibSearchList O; 608 for (auto *JD2 : S.JDSearchOrder) { 609 if (JD2 == JD) 610 continue; 611 O.push_back(std::make_pair(JD2, false)); 612 } 613 JD->setSearchOrder(std::move(O)); 614 } 615 } 616 617 // Load each object into the corresponding JITDylib.. 618 LLVM_DEBUG(dbgs() << "Adding objects...\n"); 619 for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end(); 620 InputFileItr != InputFileEnd; ++InputFileItr) { 621 unsigned InputFileArgIdx = 622 InputFiles.getPosition(InputFileItr - InputFiles.begin()); 623 StringRef InputFile = *InputFileItr; 624 auto &JD = *std::prev(IdxToJLD.lower_bound(InputFileArgIdx))->second; 625 LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile 626 << "\" to " << JD.getName() << "\n";); 627 auto ObjBuffer = 628 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile))); 629 ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer))); 630 } 631 632 // Define absolute symbols. 633 LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n"); 634 for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end(); 635 AbsDefItr != AbsDefEnd; ++AbsDefItr) { 636 unsigned AbsDefArgIdx = 637 AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin()); 638 auto &JD = *std::prev(IdxToJLD.lower_bound(AbsDefArgIdx))->second; 639 640 StringRef AbsDefStmt = *AbsDefItr; 641 size_t EqIdx = AbsDefStmt.find_first_of('='); 642 if (EqIdx == StringRef::npos) 643 return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt + 644 "\". Syntax: <name>=<addr>", 645 inconvertibleErrorCode()); 646 StringRef Name = AbsDefStmt.substr(0, EqIdx).trim(); 647 StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim(); 648 649 uint64_t Addr; 650 if (AddrStr.getAsInteger(0, Addr)) 651 return make_error<StringError>("Invalid address expression \"" + AddrStr + 652 "\" in absolute define \"" + AbsDefStmt + 653 "\"", 654 inconvertibleErrorCode()); 655 JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported); 656 if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}}))) 657 return Err; 658 659 // Register the absolute symbol with the session symbol infos. 660 S.SymbolInfos[Name] = { StringRef(), Addr }; 661 } 662 663 LLVM_DEBUG({ 664 dbgs() << "Dylib search order is [ "; 665 for (auto *JD : S.JDSearchOrder) 666 dbgs() << JD->getName() << " "; 667 dbgs() << "]\n"; 668 }); 669 670 return Error::success(); 671 } 672 673 Error runChecks(Session &S) { 674 675 auto TripleName = S.TT.str(); 676 std::string ErrorStr; 677 const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr); 678 if (!TheTarget) 679 ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName + 680 "': " + ErrorStr, 681 inconvertibleErrorCode())); 682 683 std::unique_ptr<MCSubtargetInfo> STI( 684 TheTarget->createMCSubtargetInfo(TripleName, "", "")); 685 if (!STI) 686 ExitOnErr( 687 make_error<StringError>("Unable to create subtarget for " + TripleName, 688 inconvertibleErrorCode())); 689 690 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); 691 if (!MRI) 692 ExitOnErr(make_error<StringError>("Unable to create target register info " 693 "for " + 694 TripleName, 695 inconvertibleErrorCode())); 696 697 MCTargetOptions MCOptions; 698 std::unique_ptr<MCAsmInfo> MAI( 699 TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 700 if (!MAI) 701 ExitOnErr(make_error<StringError>("Unable to create target asm info " + 702 TripleName, 703 inconvertibleErrorCode())); 704 705 MCContext Ctx(MAI.get(), MRI.get(), nullptr); 706 707 std::unique_ptr<MCDisassembler> Disassembler( 708 TheTarget->createMCDisassembler(*STI, Ctx)); 709 if (!Disassembler) 710 ExitOnErr(make_error<StringError>("Unable to create disassembler for " + 711 TripleName, 712 inconvertibleErrorCode())); 713 714 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 715 716 std::unique_ptr<MCInstPrinter> InstPrinter( 717 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI)); 718 719 auto IsSymbolValid = [&S](StringRef Symbol) { 720 return S.isSymbolRegistered(Symbol); 721 }; 722 723 auto GetSymbolInfo = [&S](StringRef Symbol) { 724 return S.findSymbolInfo(Symbol, "Can not get symbol info"); 725 }; 726 727 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) { 728 return S.findSectionInfo(FileName, SectionName); 729 }; 730 731 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) { 732 return S.findStubInfo(FileName, SectionName); 733 }; 734 735 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) { 736 return S.findGOTEntryInfo(FileName, SectionName); 737 }; 738 739 RuntimeDyldChecker Checker( 740 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo, 741 S.TT.isLittleEndian() ? support::little : support::big, 742 Disassembler.get(), InstPrinter.get(), dbgs()); 743 744 for (auto &CheckFile : CheckFiles) { 745 auto CheckerFileBuf = 746 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile))); 747 if (!Checker.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf)) 748 ExitOnErr(make_error<StringError>( 749 "Some checks in " + CheckFile + " failed", inconvertibleErrorCode())); 750 } 751 752 return Error::success(); 753 } 754 755 static void dumpSessionStats(Session &S) { 756 if (ShowSizes) 757 outs() << "Total size of all blocks before pruning: " << S.SizeBeforePruning 758 << "\nTotal size of all blocks after fixups: " << S.SizeAfterFixups 759 << "\n"; 760 } 761 762 static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) { 763 return S.ES.lookup(S.JDSearchOrder, EntryPointName); 764 } 765 766 Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) { 767 assert(EntryPoint.getAddress() && "Entry point address should not be null"); 768 769 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>"; 770 auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1); 771 strcpy(PNStorage.get(), JITProgramName); 772 773 std::vector<const char *> EntryPointArgs; 774 EntryPointArgs.push_back(PNStorage.get()); 775 for (auto &InputArg : InputArgv) 776 EntryPointArgs.push_back(InputArg.data()); 777 EntryPointArgs.push_back(nullptr); 778 779 using MainTy = int (*)(int, const char *[]); 780 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress()); 781 782 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data()); 783 } 784 785 struct JITLinkTimers { 786 TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"}; 787 Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG}; 788 Timer LinkTimer{"link", "time to link object files", JITLinkTG}; 789 Timer RunTimer{"run", "time to execute jitlink'd code", JITLinkTG}; 790 }; 791 792 int main(int argc, char *argv[]) { 793 InitLLVM X(argc, argv); 794 795 InitializeAllTargetInfos(); 796 InitializeAllTargetMCs(); 797 InitializeAllDisassemblers(); 798 799 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool"); 800 ExitOnErr.setBanner(std::string(argv[0]) + ": "); 801 802 /// If timers are enabled, create a JITLinkTimers instance. 803 std::unique_ptr<JITLinkTimers> Timers = 804 ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr; 805 806 Session S(getFirstFileTriple()); 807 808 ExitOnErr(sanitizeArguments(S)); 809 810 if (!NoProcessSymbols) 811 ExitOnErr(loadProcessSymbols(S)); 812 ExitOnErr(loadDylibs()); 813 814 815 { 816 TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr); 817 ExitOnErr(loadObjects(S)); 818 } 819 820 JITEvaluatedSymbol EntryPoint = 0; 821 { 822 TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr); 823 EntryPoint = ExitOnErr(getMainEntryPoint(S)); 824 } 825 826 if (ShowAddrs) 827 S.dumpSessionInfo(outs()); 828 829 ExitOnErr(runChecks(S)); 830 831 dumpSessionStats(S); 832 833 if (NoExec) 834 return 0; 835 836 int Result = 0; 837 { 838 TimeRegion TR(Timers ? &Timers->RunTimer : nullptr); 839 Result = ExitOnErr(runEntryPoint(S, EntryPoint)); 840 } 841 842 return Result; 843 } 844