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/Object/COFF.h" 27 #include "llvm/Object/MachO.h" 28 #include "llvm/Object/ObjectFile.h" 29 #include "llvm/Support/CommandLine.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/DynamicLibrary.h" 32 #include "llvm/Support/InitLLVM.h" 33 #include "llvm/Support/MemoryBuffer.h" 34 #include "llvm/Support/TargetRegistry.h" 35 #include "llvm/Support/TargetSelect.h" 36 37 #include <list> 38 #include <string> 39 40 #define DEBUG_TYPE "llvm-jitlink" 41 42 using namespace llvm; 43 using namespace llvm::jitlink; 44 using namespace llvm::orc; 45 46 static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore, 47 cl::desc("input files")); 48 49 static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"), 50 cl::init(false)); 51 52 static cl::list<std::string> 53 CheckFiles("check", cl::desc("File containing verifier checks"), 54 cl::ZeroOrMore); 55 56 static cl::opt<std::string> 57 EntryPointName("entry", cl::desc("Symbol to call as main entry point"), 58 cl::init("")); 59 60 static cl::list<std::string> JITLinkDylibs( 61 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent " 62 "input file arguments")); 63 64 static cl::list<std::string> 65 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"), 66 cl::ZeroOrMore); 67 68 static cl::list<std::string> InputArgv("args", cl::Positional, 69 cl::desc("<program arguments>..."), 70 cl::ZeroOrMore, cl::PositionalEatsArgs); 71 72 static cl::opt<bool> 73 NoProcessSymbols("no-process-syms", 74 cl::desc("Do not resolve to llvm-jitlink process symbols"), 75 cl::init(false)); 76 77 static cl::list<std::string> AbsoluteDefs( 78 "define-abs", 79 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"), 80 cl::ZeroOrMore); 81 82 static cl::opt<bool> ShowAddrs( 83 "show-addrs", 84 cl::desc("Print registered symbol, section, got and stub addresses"), 85 cl::init(false)); 86 87 static cl::opt<bool> ShowAtomGraph( 88 "show-graph", 89 cl::desc("Print the atom graph after fixups have been applied"), 90 cl::init(false)); 91 92 static cl::opt<bool> ShowSizes( 93 "show-sizes", 94 cl::desc("Show sizes pre- and post-dead stripping, and allocations"), 95 cl::init(false)); 96 97 static cl::opt<bool> ShowRelocatedSectionContents( 98 "show-relocated-section-contents", 99 cl::desc("show section contents after fixups have been applied"), 100 cl::init(false)); 101 102 ExitOnError ExitOnErr; 103 104 namespace llvm { 105 106 static raw_ostream & 107 operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) { 108 return OS << "target addr = " 109 << format("0x%016" PRIx64, MRI.getTargetAddress()) 110 << ", content: " << (const void *)MRI.getContent().data() << " -- " 111 << (const void *)(MRI.getContent().data() + MRI.getContent().size()) 112 << " (" << MRI.getContent().size() << " bytes)"; 113 } 114 115 static raw_ostream & 116 operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) { 117 OS << "Symbols:\n"; 118 for (auto &SKV : SIM) 119 OS << " \"" << SKV.first() << "\" " << SKV.second << "\n"; 120 return OS; 121 } 122 123 static raw_ostream & 124 operator<<(raw_ostream &OS, const Session::FileInfo &FI) { 125 for (auto &SIKV : FI.SectionInfos) 126 OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n"; 127 for (auto &GOTKV : FI.GOTEntryInfos) 128 OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n"; 129 for (auto &StubKV : FI.StubInfos) 130 OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n"; 131 return OS; 132 } 133 134 static raw_ostream & 135 operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) { 136 for (auto &FIKV : FIM) 137 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second; 138 return OS; 139 } 140 141 static uint64_t computeTotalAtomSizes(AtomGraph &G) { 142 uint64_t TotalSize = 0; 143 for (auto *DA : G.defined_atoms()) 144 if (DA->isZeroFill()) 145 TotalSize += DA->getZeroFillSize(); 146 else 147 TotalSize += DA->getContent().size(); 148 return TotalSize; 149 } 150 151 static void dumpSectionContents(raw_ostream &OS, AtomGraph &G) { 152 constexpr JITTargetAddress DumpWidth = 16; 153 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two"); 154 155 // Put sections in address order. 156 std::vector<Section *> Sections; 157 for (auto &S : G.sections()) 158 Sections.push_back(&S); 159 160 std::sort(Sections.begin(), Sections.end(), 161 [](const Section *LHS, const Section *RHS) { 162 if (LHS->atoms_empty() && RHS->atoms_empty()) 163 return false; 164 if (LHS->atoms_empty()) 165 return false; 166 if (RHS->atoms_empty()) 167 return true; 168 return (*LHS->atoms().begin())->getAddress() < 169 (*RHS->atoms().begin())->getAddress(); 170 }); 171 172 for (auto *S : Sections) { 173 OS << S->getName() << " content:"; 174 if (S->atoms_empty()) { 175 OS << "\n section empty\n"; 176 continue; 177 } 178 179 // Sort atoms into order, then render. 180 std::vector<DefinedAtom *> Atoms(S->atoms().begin(), S->atoms().end()); 181 std::sort(Atoms.begin(), Atoms.end(), 182 [](const DefinedAtom *LHS, const DefinedAtom *RHS) { 183 return LHS->getAddress() < RHS->getAddress(); 184 }); 185 186 JITTargetAddress NextAddr = Atoms.front()->getAddress() & ~(DumpWidth - 1); 187 for (auto *DA : Atoms) { 188 bool IsZeroFill = DA->isZeroFill(); 189 JITTargetAddress AtomStart = DA->getAddress(); 190 JITTargetAddress AtomSize = 191 IsZeroFill ? DA->getZeroFillSize() : DA->getContent().size(); 192 JITTargetAddress AtomEnd = AtomStart + AtomSize; 193 const uint8_t *AtomData = 194 IsZeroFill ? nullptr : DA->getContent().bytes_begin(); 195 196 // Pad any space before the atom starts. 197 while (NextAddr != AtomStart) { 198 if (NextAddr % DumpWidth == 0) 199 OS << formatv("\n{0:x16}:", NextAddr); 200 OS << " "; 201 ++NextAddr; 202 } 203 204 // Render the atom content. 205 while (NextAddr != AtomEnd) { 206 if (NextAddr % DumpWidth == 0) 207 OS << formatv("\n{0:x16}:", NextAddr); 208 if (IsZeroFill) 209 OS << " 00"; 210 else 211 OS << formatv(" {0:x-2}", AtomData[NextAddr - AtomStart]); 212 ++NextAddr; 213 } 214 } 215 OS << "\n"; 216 } 217 } 218 219 Session::Session(Triple TT) : ObjLayer(ES, MemMgr), TT(std::move(TT)) { 220 221 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the 222 /// Session. 223 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin { 224 public: 225 JITLinkSessionPlugin(Session &S) : S(S) {} 226 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, 227 PassConfiguration &PassConfig) { 228 S.modifyPassConfig(TT, PassConfig); 229 } 230 231 private: 232 Session &S; 233 }; 234 235 if (!NoExec && !TT.isOSWindows()) 236 ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>( 237 InProcessEHFrameRegistrar::getInstance())); 238 239 ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this)); 240 } 241 242 void Session::dumpSessionInfo(raw_ostream &OS) { 243 OS << "Registered addresses:\n" << SymbolInfos << FileInfos; 244 } 245 246 void Session::modifyPassConfig(const Triple &FTT, 247 PassConfiguration &PassConfig) { 248 if (!CheckFiles.empty()) 249 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) { 250 if (TT.getObjectFormat() == Triple::MachO) 251 return registerMachOStubsAndGOT(*this, G); 252 return make_error<StringError>("Unsupported object format for GOT/stub " 253 "registration", 254 inconvertibleErrorCode()); 255 }); 256 257 if (ShowAtomGraph) 258 PassConfig.PostFixupPasses.push_back([](AtomGraph &G) -> Error { 259 outs() << "Atom graph post-fixup:\n"; 260 G.dump(outs()); 261 return Error::success(); 262 }); 263 264 265 if (ShowSizes) { 266 PassConfig.PrePrunePasses.push_back([this](AtomGraph &G) -> Error { 267 SizeBeforePruning += computeTotalAtomSizes(G); 268 return Error::success(); 269 }); 270 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) -> Error { 271 SizeAfterFixups += computeTotalAtomSizes(G); 272 return Error::success(); 273 }); 274 } 275 276 if (ShowRelocatedSectionContents) 277 PassConfig.PostFixupPasses.push_back([](AtomGraph &G) -> Error { 278 outs() << "Relocated section contents for " << G.getName() << ":\n"; 279 dumpSectionContents(outs(), G); 280 return Error::success(); 281 }); 282 } 283 284 Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) { 285 auto FileInfoItr = FileInfos.find(FileName); 286 if (FileInfoItr == FileInfos.end()) 287 return make_error<StringError>("file \"" + FileName + "\" not recognized", 288 inconvertibleErrorCode()); 289 return FileInfoItr->second; 290 } 291 292 Expected<Session::MemoryRegionInfo &> 293 Session::findSectionInfo(StringRef FileName, StringRef SectionName) { 294 auto FI = findFileInfo(FileName); 295 if (!FI) 296 return FI.takeError(); 297 auto SecInfoItr = FI->SectionInfos.find(SectionName); 298 if (SecInfoItr == FI->SectionInfos.end()) 299 return make_error<StringError>("no section \"" + SectionName + 300 "\" registered for file \"" + FileName + 301 "\"", 302 inconvertibleErrorCode()); 303 return SecInfoItr->second; 304 } 305 306 Expected<Session::MemoryRegionInfo &> 307 Session::findStubInfo(StringRef FileName, StringRef TargetName) { 308 auto FI = findFileInfo(FileName); 309 if (!FI) 310 return FI.takeError(); 311 auto StubInfoItr = FI->StubInfos.find(TargetName); 312 if (StubInfoItr == FI->StubInfos.end()) 313 return make_error<StringError>("no stub for \"" + TargetName + 314 "\" registered for file \"" + FileName + 315 "\"", 316 inconvertibleErrorCode()); 317 return StubInfoItr->second; 318 } 319 320 Expected<Session::MemoryRegionInfo &> 321 Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) { 322 auto FI = findFileInfo(FileName); 323 if (!FI) 324 return FI.takeError(); 325 auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName); 326 if (GOTInfoItr == FI->GOTEntryInfos.end()) 327 return make_error<StringError>("no GOT entry for \"" + TargetName + 328 "\" registered for file \"" + FileName + 329 "\"", 330 inconvertibleErrorCode()); 331 return GOTInfoItr->second; 332 } 333 334 bool Session::isSymbolRegistered(StringRef SymbolName) { 335 return SymbolInfos.count(SymbolName); 336 } 337 338 Expected<Session::MemoryRegionInfo &> 339 Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) { 340 auto SymInfoItr = SymbolInfos.find(SymbolName); 341 if (SymInfoItr == SymbolInfos.end()) 342 return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName + 343 " not found", 344 inconvertibleErrorCode()); 345 return SymInfoItr->second; 346 } 347 348 } // end namespace llvm 349 350 Triple getFirstFileTriple() { 351 assert(!InputFiles.empty() && "InputFiles can not be empty"); 352 auto ObjBuffer = 353 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front()))); 354 auto Obj = ExitOnErr( 355 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())); 356 return Obj->makeTriple(); 357 } 358 359 Error sanitizeArguments(const Session &S) { 360 if (EntryPointName.empty()) { 361 if (S.TT.getObjectFormat() == Triple::MachO) 362 EntryPointName = "_main"; 363 else 364 EntryPointName = "main"; 365 } 366 367 if (NoExec && !InputArgv.empty()) 368 outs() << "Warning: --args passed to -noexec run will be ignored.\n"; 369 370 return Error::success(); 371 } 372 373 Error loadProcessSymbols(Session &S) { 374 std::string ErrMsg; 375 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg)) 376 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); 377 378 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0'; 379 auto InternedEntryPointName = S.ES.intern(EntryPointName); 380 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) { 381 return Name != InternedEntryPointName; 382 }; 383 S.ES.getMainJITDylib().addGenerator( 384 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( 385 GlobalPrefix, FilterMainEntryPoint))); 386 387 return Error::success(); 388 } 389 390 Error loadDylibs() { 391 // FIXME: This should all be handled inside DynamicLibrary. 392 for (const auto &Dylib : Dylibs) { 393 if (!sys::fs::is_regular_file(Dylib)) 394 return make_error<StringError>("\"" + Dylib + "\" is not a regular file", 395 inconvertibleErrorCode()); 396 std::string ErrMsg; 397 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg)) 398 return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); 399 } 400 401 return Error::success(); 402 } 403 404 Error loadObjects(Session &S) { 405 406 std::map<unsigned, JITDylib *> IdxToJLD; 407 408 // First, set up JITDylibs. 409 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n"); 410 { 411 // Create a "main" JITLinkDylib. 412 auto &MainJD = S.ES.getMainJITDylib(); 413 IdxToJLD[0] = &MainJD; 414 S.JDSearchOrder.push_back(&MainJD); 415 LLVM_DEBUG(dbgs() << " 0: " << MainJD.getName() << "\n"); 416 417 // Add any extra JITLinkDylibs from the command line. 418 std::string JDNamePrefix("lib"); 419 for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end(); 420 JLDItr != JLDEnd; ++JLDItr) { 421 auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr); 422 unsigned JDIdx = 423 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin()); 424 IdxToJLD[JDIdx] = &JD; 425 S.JDSearchOrder.push_back(&JD); 426 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n"); 427 } 428 429 // Set every dylib to link against every other, in command line order. 430 for (auto *JD : S.JDSearchOrder) { 431 JITDylibSearchList O; 432 for (auto *JD2 : S.JDSearchOrder) { 433 if (JD2 == JD) 434 continue; 435 O.push_back(std::make_pair(JD2, false)); 436 } 437 JD->setSearchOrder(std::move(O)); 438 } 439 } 440 441 // Load each object into the corresponding JITDylib.. 442 LLVM_DEBUG(dbgs() << "Adding objects...\n"); 443 for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end(); 444 InputFileItr != InputFileEnd; ++InputFileItr) { 445 unsigned InputFileArgIdx = 446 InputFiles.getPosition(InputFileItr - InputFiles.begin()); 447 StringRef InputFile = *InputFileItr; 448 auto &JD = *std::prev(IdxToJLD.lower_bound(InputFileArgIdx))->second; 449 LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile 450 << "\" to " << JD.getName() << "\n";); 451 auto ObjBuffer = 452 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile))); 453 ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer))); 454 } 455 456 // Define absolute symbols. 457 LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n"); 458 for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end(); 459 AbsDefItr != AbsDefEnd; ++AbsDefItr) { 460 unsigned AbsDefArgIdx = 461 AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin()); 462 auto &JD = *std::prev(IdxToJLD.lower_bound(AbsDefArgIdx))->second; 463 464 StringRef AbsDefStmt = *AbsDefItr; 465 size_t EqIdx = AbsDefStmt.find_first_of('='); 466 if (EqIdx == StringRef::npos) 467 return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt + 468 "\". Syntax: <name>=<addr>", 469 inconvertibleErrorCode()); 470 StringRef Name = AbsDefStmt.substr(0, EqIdx).trim(); 471 StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim(); 472 473 uint64_t Addr; 474 if (AddrStr.getAsInteger(0, Addr)) 475 return make_error<StringError>("Invalid address expression \"" + AddrStr + 476 "\" in absolute define \"" + AbsDefStmt + 477 "\"", 478 inconvertibleErrorCode()); 479 JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported); 480 if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}}))) 481 return Err; 482 483 // Register the absolute symbol with the session symbol infos. 484 S.SymbolInfos[Name] = { StringRef(), Addr }; 485 } 486 487 LLVM_DEBUG({ 488 dbgs() << "Dylib search order is [ "; 489 for (auto *JD : S.JDSearchOrder) 490 dbgs() << JD->getName() << " "; 491 dbgs() << "]\n"; 492 }); 493 494 return Error::success(); 495 } 496 497 Error runChecks(Session &S) { 498 499 auto TripleName = S.TT.str(); 500 std::string ErrorStr; 501 const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr); 502 if (!TheTarget) 503 ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName + 504 "': " + ErrorStr, 505 inconvertibleErrorCode())); 506 507 std::unique_ptr<MCSubtargetInfo> STI( 508 TheTarget->createMCSubtargetInfo(TripleName, "", "")); 509 if (!STI) 510 ExitOnErr( 511 make_error<StringError>("Unable to create subtarget for " + TripleName, 512 inconvertibleErrorCode())); 513 514 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); 515 if (!MRI) 516 ExitOnErr(make_error<StringError>("Unable to create target register info " 517 "for " + 518 TripleName, 519 inconvertibleErrorCode())); 520 521 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); 522 if (!MAI) 523 ExitOnErr(make_error<StringError>("Unable to create target asm info " + 524 TripleName, 525 inconvertibleErrorCode())); 526 527 MCContext Ctx(MAI.get(), MRI.get(), nullptr); 528 529 std::unique_ptr<MCDisassembler> Disassembler( 530 TheTarget->createMCDisassembler(*STI, Ctx)); 531 if (!Disassembler) 532 ExitOnErr(make_error<StringError>("Unable to create disassembler for " + 533 TripleName, 534 inconvertibleErrorCode())); 535 536 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 537 538 std::unique_ptr<MCInstPrinter> InstPrinter( 539 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI)); 540 541 auto IsSymbolValid = [&S](StringRef Symbol) { 542 return S.isSymbolRegistered(Symbol); 543 }; 544 545 auto GetSymbolInfo = [&S](StringRef Symbol) { 546 return S.findSymbolInfo(Symbol, "Can not get symbol info"); 547 }; 548 549 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) { 550 return S.findSectionInfo(FileName, SectionName); 551 }; 552 553 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) { 554 return S.findStubInfo(FileName, SectionName); 555 }; 556 557 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) { 558 return S.findGOTEntryInfo(FileName, SectionName); 559 }; 560 561 RuntimeDyldChecker Checker( 562 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo, 563 S.TT.isLittleEndian() ? support::little : support::big, 564 Disassembler.get(), InstPrinter.get(), dbgs()); 565 566 for (auto &CheckFile : CheckFiles) { 567 auto CheckerFileBuf = 568 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile))); 569 if (!Checker.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf)) 570 ExitOnErr(make_error<StringError>( 571 "Some checks in " + CheckFile + " failed", inconvertibleErrorCode())); 572 } 573 574 return Error::success(); 575 } 576 577 static void dumpSessionStats(Session &S) { 578 if (ShowSizes) 579 outs() << "Total size of all atoms before pruning: " << S.SizeBeforePruning 580 << "\nTotal size of all atoms after fixups: " << S.SizeAfterFixups 581 << "\n"; 582 } 583 584 static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) { 585 return S.ES.lookup(S.JDSearchOrder, EntryPointName); 586 } 587 588 Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) { 589 assert(EntryPoint.getAddress() && "Entry point address should not be null"); 590 591 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>"; 592 auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1); 593 strcpy(PNStorage.get(), JITProgramName); 594 595 std::vector<const char *> EntryPointArgs; 596 EntryPointArgs.push_back(PNStorage.get()); 597 for (auto &InputArg : InputArgv) 598 EntryPointArgs.push_back(InputArg.data()); 599 EntryPointArgs.push_back(nullptr); 600 601 using MainTy = int (*)(int, const char *[]); 602 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress()); 603 604 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data()); 605 } 606 607 int main(int argc, char *argv[]) { 608 InitLLVM X(argc, argv); 609 610 InitializeAllTargetInfos(); 611 InitializeAllTargetMCs(); 612 InitializeAllDisassemblers(); 613 614 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool"); 615 ExitOnErr.setBanner(std::string(argv[0]) + ": "); 616 617 Session S(getFirstFileTriple()); 618 619 ExitOnErr(sanitizeArguments(S)); 620 621 if (!NoProcessSymbols) 622 ExitOnErr(loadProcessSymbols(S)); 623 ExitOnErr(loadDylibs()); 624 625 ExitOnErr(loadObjects(S)); 626 627 auto EntryPoint = ExitOnErr(getMainEntryPoint(S)); 628 629 if (ShowAddrs) 630 S.dumpSessionInfo(outs()); 631 632 ExitOnErr(runChecks(S)); 633 634 dumpSessionStats(S); 635 636 if (NoExec) 637 return 0; 638 639 return ExitOnErr(runEntryPoint(S, EntryPoint)); 640 } 641