[llvm-readobj] - Fix a TODO in elf-reloc-zero-name-or-value.test.
[llvm-complete.git] / tools / llvm-jitlink / llvm-jitlink.cpp
blobdfee97241a9aa4f2422fc4b7321028394505d5f7
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/Process.h"
35 #include "llvm/Support/TargetRegistry.h"
36 #include "llvm/Support/TargetSelect.h"
37 #include "llvm/Support/Timer.h"
39 #include <list>
40 #include <string>
42 #define DEBUG_TYPE "llvm-jitlink"
44 using namespace llvm;
45 using namespace llvm::jitlink;
46 using namespace llvm::orc;
48 static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
49 cl::desc("input files"));
51 static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
52 cl::init(false));
54 static cl::list<std::string>
55 CheckFiles("check", cl::desc("File containing verifier checks"),
56 cl::ZeroOrMore);
58 static cl::opt<std::string>
59 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
60 cl::init(""));
62 static cl::list<std::string> JITLinkDylibs(
63 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
64 "input file arguments"));
66 static cl::list<std::string>
67 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
68 cl::ZeroOrMore);
70 static cl::list<std::string> InputArgv("args", cl::Positional,
71 cl::desc("<program arguments>..."),
72 cl::ZeroOrMore, cl::PositionalEatsArgs);
74 static cl::opt<bool>
75 NoProcessSymbols("no-process-syms",
76 cl::desc("Do not resolve to llvm-jitlink process symbols"),
77 cl::init(false));
79 static cl::list<std::string> AbsoluteDefs(
80 "define-abs",
81 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
82 cl::ZeroOrMore);
84 static cl::opt<bool> ShowAddrs(
85 "show-addrs",
86 cl::desc("Print registered symbol, section, got and stub addresses"),
87 cl::init(false));
89 static cl::opt<bool> ShowAtomGraph(
90 "show-graph",
91 cl::desc("Print the atom graph after fixups have been applied"),
92 cl::init(false));
94 static cl::opt<bool> ShowSizes(
95 "show-sizes",
96 cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
97 cl::init(false));
99 static cl::opt<bool> ShowTimes("show-times",
100 cl::desc("Show times for llvm-jitlink phases"),
101 cl::init(false));
103 static cl::opt<std::string> SlabAllocateSizeString(
104 "slab-allocate",
105 cl::desc("Allocate from a slab of the given size "
106 "(allowable suffixes: Kb, Mb, Gb. default = "
107 "Kb)"),
108 cl::init(""));
110 static cl::opt<bool> ShowRelocatedSectionContents(
111 "show-relocated-section-contents",
112 cl::desc("show section contents after fixups have been applied"),
113 cl::init(false));
115 ExitOnError ExitOnErr;
117 namespace llvm {
119 static raw_ostream &
120 operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
121 return OS << "target addr = "
122 << format("0x%016" PRIx64, MRI.getTargetAddress())
123 << ", content: " << (const void *)MRI.getContent().data() << " -- "
124 << (const void *)(MRI.getContent().data() + MRI.getContent().size())
125 << " (" << MRI.getContent().size() << " bytes)";
128 static raw_ostream &
129 operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) {
130 OS << "Symbols:\n";
131 for (auto &SKV : SIM)
132 OS << " \"" << SKV.first() << "\" " << SKV.second << "\n";
133 return OS;
136 static raw_ostream &
137 operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
138 for (auto &SIKV : FI.SectionInfos)
139 OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
140 for (auto &GOTKV : FI.GOTEntryInfos)
141 OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
142 for (auto &StubKV : FI.StubInfos)
143 OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
144 return OS;
147 static raw_ostream &
148 operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) {
149 for (auto &FIKV : FIM)
150 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second;
151 return OS;
154 static uint64_t computeTotalAtomSizes(AtomGraph &G) {
155 uint64_t TotalSize = 0;
156 for (auto *DA : G.defined_atoms())
157 if (DA->isZeroFill())
158 TotalSize += DA->getZeroFillSize();
159 else
160 TotalSize += DA->getContent().size();
161 return TotalSize;
164 static void dumpSectionContents(raw_ostream &OS, AtomGraph &G) {
165 constexpr JITTargetAddress DumpWidth = 16;
166 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two");
168 // Put sections in address order.
169 std::vector<Section *> Sections;
170 for (auto &S : G.sections())
171 Sections.push_back(&S);
173 std::sort(Sections.begin(), Sections.end(),
174 [](const Section *LHS, const Section *RHS) {
175 if (LHS->atoms_empty() && RHS->atoms_empty())
176 return false;
177 if (LHS->atoms_empty())
178 return false;
179 if (RHS->atoms_empty())
180 return true;
181 return (*LHS->atoms().begin())->getAddress() <
182 (*RHS->atoms().begin())->getAddress();
185 for (auto *S : Sections) {
186 OS << S->getName() << " content:";
187 if (S->atoms_empty()) {
188 OS << "\n section empty\n";
189 continue;
192 // Sort atoms into order, then render.
193 std::vector<DefinedAtom *> Atoms(S->atoms().begin(), S->atoms().end());
194 std::sort(Atoms.begin(), Atoms.end(),
195 [](const DefinedAtom *LHS, const DefinedAtom *RHS) {
196 return LHS->getAddress() < RHS->getAddress();
199 JITTargetAddress NextAddr = Atoms.front()->getAddress() & ~(DumpWidth - 1);
200 for (auto *DA : Atoms) {
201 bool IsZeroFill = DA->isZeroFill();
202 JITTargetAddress AtomStart = DA->getAddress();
203 JITTargetAddress AtomSize =
204 IsZeroFill ? DA->getZeroFillSize() : DA->getContent().size();
205 JITTargetAddress AtomEnd = AtomStart + AtomSize;
206 const uint8_t *AtomData =
207 IsZeroFill ? nullptr : DA->getContent().bytes_begin();
209 // Pad any space before the atom starts.
210 while (NextAddr != AtomStart) {
211 if (NextAddr % DumpWidth == 0)
212 OS << formatv("\n{0:x16}:", NextAddr);
213 OS << " ";
214 ++NextAddr;
217 // Render the atom content.
218 while (NextAddr != AtomEnd) {
219 if (NextAddr % DumpWidth == 0)
220 OS << formatv("\n{0:x16}:", NextAddr);
221 if (IsZeroFill)
222 OS << " 00";
223 else
224 OS << formatv(" {0:x-2}", AtomData[NextAddr - AtomStart]);
225 ++NextAddr;
228 OS << "\n";
232 class JITLinkSlabAllocator final : public JITLinkMemoryManager {
233 public:
234 static Expected<std::unique_ptr<JITLinkSlabAllocator>>
235 Create(uint64_t SlabSize) {
236 Error Err = Error::success();
237 std::unique_ptr<JITLinkSlabAllocator> Allocator(
238 new JITLinkSlabAllocator(SlabSize, Err));
239 if (Err)
240 return std::move(Err);
241 return std::move(Allocator);
244 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
245 allocate(const SegmentsRequestMap &Request) override {
247 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
249 // Local class for allocation.
250 class IPMMAlloc : public Allocation {
251 public:
252 IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
253 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
254 assert(SegBlocks.count(Seg) && "No allocation for segment");
255 return {static_cast<char *>(SegBlocks[Seg].base()),
256 SegBlocks[Seg].allocatedSize()};
258 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
259 assert(SegBlocks.count(Seg) && "No allocation for segment");
260 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
262 void finalizeAsync(FinalizeContinuation OnFinalize) override {
263 OnFinalize(applyProtections());
265 Error deallocate() override {
266 for (auto &KV : SegBlocks)
267 if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
268 return errorCodeToError(EC);
269 return Error::success();
272 private:
273 Error applyProtections() {
274 for (auto &KV : SegBlocks) {
275 auto &Prot = KV.first;
276 auto &Block = KV.second;
277 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
278 return errorCodeToError(EC);
279 if (Prot & sys::Memory::MF_EXEC)
280 sys::Memory::InvalidateInstructionCache(Block.base(),
281 Block.allocatedSize());
283 return Error::success();
286 AllocationMap SegBlocks;
289 AllocationMap Blocks;
291 for (auto &KV : Request) {
292 auto &Seg = KV.second;
294 if (Seg.getContentAlignment() > PageSize)
295 return make_error<StringError>("Cannot request higher than page "
296 "alignment",
297 inconvertibleErrorCode());
299 if (PageSize % Seg.getContentAlignment() != 0)
300 return make_error<StringError>("Page size is not a multiple of "
301 "alignment",
302 inconvertibleErrorCode());
304 uint64_t ZeroFillStart =
305 alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment());
306 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
308 // Round segment size up to page boundary.
309 SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1);
311 // Take segment bytes from the front of the slab.
312 void *SlabBase = SlabRemaining.base();
313 uint64_t SlabRemainingSize = SlabRemaining.allocatedSize();
315 if (SegmentSize > SlabRemainingSize)
316 return make_error<StringError>("Slab allocator out of memory",
317 inconvertibleErrorCode());
319 sys::MemoryBlock SegMem(SlabBase, SegmentSize);
320 SlabRemaining =
321 sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize,
322 SlabRemainingSize - SegmentSize);
324 // Zero out the zero-fill memory.
325 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
326 Seg.getZeroFillSize());
328 // Record the block for this segment.
329 Blocks[KV.first] = std::move(SegMem);
331 return std::unique_ptr<InProcessMemoryManager::Allocation>(
332 new IPMMAlloc(std::move(Blocks)));
335 private:
336 JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
337 ErrorAsOutParameter _(&Err);
339 PageSize = sys::Process::getPageSizeEstimate();
341 if (!isPowerOf2_64(PageSize)) {
342 Err = make_error<StringError>("Page size is not a power of 2",
343 inconvertibleErrorCode());
344 return;
347 // Round slab request up to page size.
348 SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
350 const sys::Memory::ProtectionFlags ReadWrite =
351 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
352 sys::Memory::MF_WRITE);
354 std::error_code EC;
355 SlabRemaining =
356 sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
358 if (EC) {
359 Err = errorCodeToError(EC);
360 return;
364 sys::MemoryBlock SlabRemaining;
365 uint64_t PageSize = 0;
368 Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
369 SizeString = SizeString.trim();
371 uint64_t Units = 1024;
373 if (SizeString.endswith_lower("kb"))
374 SizeString = SizeString.drop_back(2).rtrim();
375 else if (SizeString.endswith_lower("mb")) {
376 Units = 1024 * 1024;
377 SizeString = SizeString.drop_back(2).rtrim();
378 } else if (SizeString.endswith_lower("gb")) {
379 Units = 1024 * 1024 * 1024;
380 SizeString = SizeString.drop_back(2).rtrim();
383 uint64_t SlabSize = 0;
384 if (SizeString.getAsInteger(10, SlabSize))
385 return make_error<StringError>("Invalid numeric format for slab size",
386 inconvertibleErrorCode());
388 return SlabSize * Units;
391 static std::unique_ptr<jitlink::JITLinkMemoryManager> createMemoryManager() {
392 if (!SlabAllocateSizeString.empty()) {
393 auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
394 return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
396 return std::make_unique<jitlink::InProcessMemoryManager>();
399 Session::Session(Triple TT)
400 : MemMgr(createMemoryManager()), ObjLayer(ES, *MemMgr), TT(std::move(TT)) {
402 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
403 /// Session.
404 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
405 public:
406 JITLinkSessionPlugin(Session &S) : S(S) {}
407 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
408 PassConfiguration &PassConfig) {
409 S.modifyPassConfig(TT, PassConfig);
412 private:
413 Session &S;
416 if (!NoExec && !TT.isOSWindows())
417 ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
418 InProcessEHFrameRegistrar::getInstance()));
420 ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
423 void Session::dumpSessionInfo(raw_ostream &OS) {
424 OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
427 void Session::modifyPassConfig(const Triple &FTT,
428 PassConfiguration &PassConfig) {
429 if (!CheckFiles.empty())
430 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) {
431 if (TT.getObjectFormat() == Triple::MachO)
432 return registerMachOStubsAndGOT(*this, G);
433 return make_error<StringError>("Unsupported object format for GOT/stub "
434 "registration",
435 inconvertibleErrorCode());
438 if (ShowAtomGraph)
439 PassConfig.PostFixupPasses.push_back([](AtomGraph &G) -> Error {
440 outs() << "Atom graph post-fixup:\n";
441 G.dump(outs());
442 return Error::success();
446 if (ShowSizes) {
447 PassConfig.PrePrunePasses.push_back([this](AtomGraph &G) -> Error {
448 SizeBeforePruning += computeTotalAtomSizes(G);
449 return Error::success();
451 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) -> Error {
452 SizeAfterFixups += computeTotalAtomSizes(G);
453 return Error::success();
457 if (ShowRelocatedSectionContents)
458 PassConfig.PostFixupPasses.push_back([](AtomGraph &G) -> Error {
459 outs() << "Relocated section contents for " << G.getName() << ":\n";
460 dumpSectionContents(outs(), G);
461 return Error::success();
465 Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) {
466 auto FileInfoItr = FileInfos.find(FileName);
467 if (FileInfoItr == FileInfos.end())
468 return make_error<StringError>("file \"" + FileName + "\" not recognized",
469 inconvertibleErrorCode());
470 return FileInfoItr->second;
473 Expected<Session::MemoryRegionInfo &>
474 Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
475 auto FI = findFileInfo(FileName);
476 if (!FI)
477 return FI.takeError();
478 auto SecInfoItr = FI->SectionInfos.find(SectionName);
479 if (SecInfoItr == FI->SectionInfos.end())
480 return make_error<StringError>("no section \"" + SectionName +
481 "\" registered for file \"" + FileName +
482 "\"",
483 inconvertibleErrorCode());
484 return SecInfoItr->second;
487 Expected<Session::MemoryRegionInfo &>
488 Session::findStubInfo(StringRef FileName, StringRef TargetName) {
489 auto FI = findFileInfo(FileName);
490 if (!FI)
491 return FI.takeError();
492 auto StubInfoItr = FI->StubInfos.find(TargetName);
493 if (StubInfoItr == FI->StubInfos.end())
494 return make_error<StringError>("no stub for \"" + TargetName +
495 "\" registered for file \"" + FileName +
496 "\"",
497 inconvertibleErrorCode());
498 return StubInfoItr->second;
501 Expected<Session::MemoryRegionInfo &>
502 Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) {
503 auto FI = findFileInfo(FileName);
504 if (!FI)
505 return FI.takeError();
506 auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName);
507 if (GOTInfoItr == FI->GOTEntryInfos.end())
508 return make_error<StringError>("no GOT entry for \"" + TargetName +
509 "\" registered for file \"" + FileName +
510 "\"",
511 inconvertibleErrorCode());
512 return GOTInfoItr->second;
515 bool Session::isSymbolRegistered(StringRef SymbolName) {
516 return SymbolInfos.count(SymbolName);
519 Expected<Session::MemoryRegionInfo &>
520 Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
521 auto SymInfoItr = SymbolInfos.find(SymbolName);
522 if (SymInfoItr == SymbolInfos.end())
523 return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName +
524 " not found",
525 inconvertibleErrorCode());
526 return SymInfoItr->second;
529 } // end namespace llvm
531 Triple getFirstFileTriple() {
532 assert(!InputFiles.empty() && "InputFiles can not be empty");
533 auto ObjBuffer =
534 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
535 auto Obj = ExitOnErr(
536 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
537 return Obj->makeTriple();
540 Error sanitizeArguments(const Session &S) {
541 if (EntryPointName.empty()) {
542 if (S.TT.getObjectFormat() == Triple::MachO)
543 EntryPointName = "_main";
544 else
545 EntryPointName = "main";
548 if (NoExec && !InputArgv.empty())
549 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
551 return Error::success();
554 Error loadProcessSymbols(Session &S) {
555 std::string ErrMsg;
556 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg))
557 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
559 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0';
560 auto InternedEntryPointName = S.ES.intern(EntryPointName);
561 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
562 return Name != InternedEntryPointName;
564 S.ES.getMainJITDylib().addGenerator(
565 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
566 GlobalPrefix, FilterMainEntryPoint)));
568 return Error::success();
571 Error loadDylibs() {
572 // FIXME: This should all be handled inside DynamicLibrary.
573 for (const auto &Dylib : Dylibs) {
574 if (!sys::fs::is_regular_file(Dylib))
575 return make_error<StringError>("\"" + Dylib + "\" is not a regular file",
576 inconvertibleErrorCode());
577 std::string ErrMsg;
578 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
579 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
582 return Error::success();
585 Error loadObjects(Session &S) {
587 std::map<unsigned, JITDylib *> IdxToJLD;
589 // First, set up JITDylibs.
590 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
592 // Create a "main" JITLinkDylib.
593 auto &MainJD = S.ES.getMainJITDylib();
594 IdxToJLD[0] = &MainJD;
595 S.JDSearchOrder.push_back(&MainJD);
596 LLVM_DEBUG(dbgs() << " 0: " << MainJD.getName() << "\n");
598 // Add any extra JITLinkDylibs from the command line.
599 std::string JDNamePrefix("lib");
600 for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end();
601 JLDItr != JLDEnd; ++JLDItr) {
602 auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr);
603 unsigned JDIdx =
604 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin());
605 IdxToJLD[JDIdx] = &JD;
606 S.JDSearchOrder.push_back(&JD);
607 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n");
610 // Set every dylib to link against every other, in command line order.
611 for (auto *JD : S.JDSearchOrder) {
612 JITDylibSearchList O;
613 for (auto *JD2 : S.JDSearchOrder) {
614 if (JD2 == JD)
615 continue;
616 O.push_back(std::make_pair(JD2, false));
618 JD->setSearchOrder(std::move(O));
622 // Load each object into the corresponding JITDylib..
623 LLVM_DEBUG(dbgs() << "Adding objects...\n");
624 for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
625 InputFileItr != InputFileEnd; ++InputFileItr) {
626 unsigned InputFileArgIdx =
627 InputFiles.getPosition(InputFileItr - InputFiles.begin());
628 StringRef InputFile = *InputFileItr;
629 auto &JD = *std::prev(IdxToJLD.lower_bound(InputFileArgIdx))->second;
630 LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
631 << "\" to " << JD.getName() << "\n";);
632 auto ObjBuffer =
633 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile)));
634 ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer)));
637 // Define absolute symbols.
638 LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n");
639 for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end();
640 AbsDefItr != AbsDefEnd; ++AbsDefItr) {
641 unsigned AbsDefArgIdx =
642 AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin());
643 auto &JD = *std::prev(IdxToJLD.lower_bound(AbsDefArgIdx))->second;
645 StringRef AbsDefStmt = *AbsDefItr;
646 size_t EqIdx = AbsDefStmt.find_first_of('=');
647 if (EqIdx == StringRef::npos)
648 return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt +
649 "\". Syntax: <name>=<addr>",
650 inconvertibleErrorCode());
651 StringRef Name = AbsDefStmt.substr(0, EqIdx).trim();
652 StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim();
654 uint64_t Addr;
655 if (AddrStr.getAsInteger(0, Addr))
656 return make_error<StringError>("Invalid address expression \"" + AddrStr +
657 "\" in absolute define \"" + AbsDefStmt +
658 "\"",
659 inconvertibleErrorCode());
660 JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported);
661 if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}})))
662 return Err;
664 // Register the absolute symbol with the session symbol infos.
665 S.SymbolInfos[Name] = { StringRef(), Addr };
668 LLVM_DEBUG({
669 dbgs() << "Dylib search order is [ ";
670 for (auto *JD : S.JDSearchOrder)
671 dbgs() << JD->getName() << " ";
672 dbgs() << "]\n";
675 return Error::success();
678 Error runChecks(Session &S) {
680 auto TripleName = S.TT.str();
681 std::string ErrorStr;
682 const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr);
683 if (!TheTarget)
684 ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName +
685 "': " + ErrorStr,
686 inconvertibleErrorCode()));
688 std::unique_ptr<MCSubtargetInfo> STI(
689 TheTarget->createMCSubtargetInfo(TripleName, "", ""));
690 if (!STI)
691 ExitOnErr(
692 make_error<StringError>("Unable to create subtarget for " + TripleName,
693 inconvertibleErrorCode()));
695 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
696 if (!MRI)
697 ExitOnErr(make_error<StringError>("Unable to create target register info "
698 "for " +
699 TripleName,
700 inconvertibleErrorCode()));
702 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
703 if (!MAI)
704 ExitOnErr(make_error<StringError>("Unable to create target asm info " +
705 TripleName,
706 inconvertibleErrorCode()));
708 MCContext Ctx(MAI.get(), MRI.get(), nullptr);
710 std::unique_ptr<MCDisassembler> Disassembler(
711 TheTarget->createMCDisassembler(*STI, Ctx));
712 if (!Disassembler)
713 ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
714 TripleName,
715 inconvertibleErrorCode()));
717 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
719 std::unique_ptr<MCInstPrinter> InstPrinter(
720 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
722 auto IsSymbolValid = [&S](StringRef Symbol) {
723 return S.isSymbolRegistered(Symbol);
726 auto GetSymbolInfo = [&S](StringRef Symbol) {
727 return S.findSymbolInfo(Symbol, "Can not get symbol info");
730 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
731 return S.findSectionInfo(FileName, SectionName);
734 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
735 return S.findStubInfo(FileName, SectionName);
738 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
739 return S.findGOTEntryInfo(FileName, SectionName);
742 RuntimeDyldChecker Checker(
743 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
744 S.TT.isLittleEndian() ? support::little : support::big,
745 Disassembler.get(), InstPrinter.get(), dbgs());
747 for (auto &CheckFile : CheckFiles) {
748 auto CheckerFileBuf =
749 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile)));
750 if (!Checker.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf))
751 ExitOnErr(make_error<StringError>(
752 "Some checks in " + CheckFile + " failed", inconvertibleErrorCode()));
755 return Error::success();
758 static void dumpSessionStats(Session &S) {
759 if (ShowSizes)
760 outs() << "Total size of all atoms before pruning: " << S.SizeBeforePruning
761 << "\nTotal size of all atoms after fixups: " << S.SizeAfterFixups
762 << "\n";
765 static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
766 return S.ES.lookup(S.JDSearchOrder, EntryPointName);
769 Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
770 assert(EntryPoint.getAddress() && "Entry point address should not be null");
772 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
773 auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1);
774 strcpy(PNStorage.get(), JITProgramName);
776 std::vector<const char *> EntryPointArgs;
777 EntryPointArgs.push_back(PNStorage.get());
778 for (auto &InputArg : InputArgv)
779 EntryPointArgs.push_back(InputArg.data());
780 EntryPointArgs.push_back(nullptr);
782 using MainTy = int (*)(int, const char *[]);
783 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
785 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
788 struct JITLinkTimers {
789 TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"};
790 Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG};
791 Timer LinkTimer{"link", "time to link object files", JITLinkTG};
792 Timer RunTimer{"run", "time to execute jitlink'd code", JITLinkTG};
795 int main(int argc, char *argv[]) {
796 InitLLVM X(argc, argv);
798 InitializeAllTargetInfos();
799 InitializeAllTargetMCs();
800 InitializeAllDisassemblers();
802 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
803 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
805 /// If timers are enabled, create a JITLinkTimers instance.
806 std::unique_ptr<JITLinkTimers> Timers =
807 ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
809 Session S(getFirstFileTriple());
811 ExitOnErr(sanitizeArguments(S));
813 if (!NoProcessSymbols)
814 ExitOnErr(loadProcessSymbols(S));
815 ExitOnErr(loadDylibs());
819 TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
820 ExitOnErr(loadObjects(S));
823 JITEvaluatedSymbol EntryPoint = 0;
825 TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);
826 EntryPoint = ExitOnErr(getMainEntryPoint(S));
829 if (ShowAddrs)
830 S.dumpSessionInfo(outs());
832 ExitOnErr(runChecks(S));
834 dumpSessionStats(S);
836 if (NoExec)
837 return 0;
839 int Result = 0;
841 TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
842 Result = ExitOnErr(runEntryPoint(S, EntryPoint));
845 return Result;