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