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