[LLVM][Alignment] Introduce Alignment In Attributes
[llvm-core.git] / tools / llvm-jitlink / llvm-jitlink.cpp
blobeff2ec18bc52378ece8a6a77a4176e12c8503667
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.
13 //===----------------------------------------------------------------------===//
15 #include "llvm-jitlink.h"
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"
37 #include <list>
38 #include <string>
40 #define DEBUG_TYPE "llvm-jitlink"
42 using namespace llvm;
43 using namespace llvm::jitlink;
44 using namespace llvm::orc;
46 static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
47 cl::desc("input files"));
49 static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
50 cl::init(false));
52 static cl::list<std::string>
53 CheckFiles("check", cl::desc("File containing verifier checks"),
54 cl::ZeroOrMore);
56 static cl::opt<std::string>
57 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
58 cl::init(""));
60 static cl::list<std::string> JITLinkDylibs(
61 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
62 "input file arguments"));
64 static cl::list<std::string>
65 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
66 cl::ZeroOrMore);
68 static cl::list<std::string> InputArgv("args", cl::Positional,
69 cl::desc("<program arguments>..."),
70 cl::ZeroOrMore, cl::PositionalEatsArgs);
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));
77 static cl::list<std::string> AbsoluteDefs(
78 "define-abs",
79 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
80 cl::ZeroOrMore);
82 static cl::opt<bool> ShowAddrs(
83 "show-addrs",
84 cl::desc("Print registered symbol, section, got and stub addresses"),
85 cl::init(false));
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));
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));
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));
102 ExitOnError ExitOnErr;
104 namespace llvm {
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)";
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;
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;
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;
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;
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");
155 // Put sections in address order.
156 std::vector<Section *> Sections;
157 for (auto &S : G.sections())
158 Sections.push_back(&S);
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();
172 for (auto *S : Sections) {
173 OS << S->getName() << " content:";
174 if (S->atoms_empty()) {
175 OS << "\n section empty\n";
176 continue;
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();
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();
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;
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;
215 OS << "\n";
219 Session::Session(Triple TT) : ObjLayer(ES, MemMgr), TT(std::move(TT)) {
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);
231 private:
232 Session &S;
235 if (!NoExec && !TT.isOSWindows())
236 ObjLayer.addPlugin(llvm::make_unique<EHFrameRegistrationPlugin>(
237 InProcessEHFrameRegistrar::getInstance()));
239 ObjLayer.addPlugin(llvm::make_unique<JITLinkSessionPlugin>(*this));
242 void Session::dumpSessionInfo(raw_ostream &OS) {
243 OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
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());
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();
265 if (ShowSizes) {
266 PassConfig.PrePrunePasses.push_back([this](AtomGraph &G) -> Error {
267 SizeBeforePruning += computeTotalAtomSizes(G);
268 return Error::success();
270 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) -> Error {
271 SizeAfterFixups += computeTotalAtomSizes(G);
272 return Error::success();
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();
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;
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;
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;
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;
334 bool Session::isSymbolRegistered(StringRef SymbolName) {
335 return SymbolInfos.count(SymbolName);
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;
348 } // end namespace llvm
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();
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";
367 if (NoExec && !InputArgv.empty())
368 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
370 return Error::success();
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());
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;
383 S.ES.getMainJITDylib().setGenerator(
384 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
385 GlobalPrefix, FilterMainEntryPoint)));
387 return Error::success();
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());
401 return Error::success();
404 Error loadObjects(Session &S) {
406 std::map<unsigned, JITDylib *> IdxToJLD;
408 // First, set up JITDylibs.
409 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
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");
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");
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));
437 JD->setSearchOrder(std::move(O));
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)));
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;
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();
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;
483 // Register the absolute symbol with the session symbol infos.
484 S.SymbolInfos[Name] = { StringRef(), Addr };
487 LLVM_DEBUG({
488 dbgs() << "Dylib search order is [ ";
489 for (auto *JD : S.JDSearchOrder)
490 dbgs() << JD->getName() << " ";
491 dbgs() << "]\n";
494 return Error::success();
497 Error runChecks(Session &S) {
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()));
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()));
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()));
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()));
527 MCContext Ctx(MAI.get(), MRI.get(), nullptr);
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()));
536 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
538 std::unique_ptr<MCInstPrinter> InstPrinter(
539 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
541 auto IsSymbolValid = [&S](StringRef Symbol) {
542 return S.isSymbolRegistered(Symbol);
545 auto GetSymbolInfo = [&S](StringRef Symbol) {
546 return S.findSymbolInfo(Symbol, "Can not get symbol info");
549 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
550 return S.findSectionInfo(FileName, SectionName);
553 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
554 return S.findStubInfo(FileName, SectionName);
557 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
558 return S.findGOTEntryInfo(FileName, SectionName);
561 RuntimeDyldChecker Checker(
562 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
563 S.TT.isLittleEndian() ? support::little : support::big,
564 Disassembler.get(), InstPrinter.get(), dbgs());
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()));
574 return Error::success();
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";
584 static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
585 return S.ES.lookup(S.JDSearchOrder, EntryPointName);
588 Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
589 assert(EntryPoint.getAddress() && "Entry point address should not be null");
591 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
592 auto PNStorage = llvm::make_unique<char[]>(strlen(JITProgramName) + 1);
593 strcpy(PNStorage.get(), JITProgramName);
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);
601 using MainTy = int (*)(int, const char *[]);
602 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
604 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
607 int main(int argc, char *argv[]) {
608 InitLLVM X(argc, argv);
610 InitializeAllTargetInfos();
611 InitializeAllTargetMCs();
612 InitializeAllDisassemblers();
614 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
615 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
617 Session S(getFirstFileTriple());
619 ExitOnErr(sanitizeArguments(S));
621 if (!NoProcessSymbols)
622 ExitOnErr(loadProcessSymbols(S));
623 ExitOnErr(loadDylibs());
625 ExitOnErr(loadObjects(S));
627 auto EntryPoint = ExitOnErr(getMainEntryPoint(S));
629 if (ShowAddrs)
630 S.dumpSessionInfo(outs());
632 ExitOnErr(runChecks(S));
634 dumpSessionStats(S);
636 if (NoExec)
637 return 0;
639 return ExitOnErr(runEntryPoint(S, EntryPoint));