1 //===- llvm-jitlink.cpp -- Command line interface/tester for llvm-jitlink -===//
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
7 //===----------------------------------------------------------------------===//
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"
42 #define DEBUG_TYPE "llvm-jitlink"
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"),
54 static cl::list
<std::string
>
55 CheckFiles("check", cl::desc("File containing verifier checks"),
58 static cl::opt
<std::string
>
59 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
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"),
70 static cl::list
<std::string
> InputArgv("args", cl::Positional
,
71 cl::desc("<program arguments>..."),
72 cl::ZeroOrMore
, cl::PositionalEatsArgs
);
75 NoProcessSymbols("no-process-syms",
76 cl::desc("Do not resolve to llvm-jitlink process symbols"),
79 static cl::list
<std::string
> AbsoluteDefs(
81 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
84 static cl::opt
<bool> ShowAddrs(
86 cl::desc("Print registered symbol, section, got and stub addresses"),
89 static cl::opt
<bool> ShowAtomGraph(
91 cl::desc("Print the atom graph after fixups have been applied"),
94 static cl::opt
<bool> ShowSizes(
96 cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
99 static cl::opt
<bool> ShowTimes("show-times",
100 cl::desc("Show times for llvm-jitlink phases"),
103 static cl::opt
<std::string
> SlabAllocateSizeString(
105 cl::desc("Allocate from a slab of the given size "
106 "(allowable suffixes: Kb, Mb, Gb. default = "
110 static cl::opt
<bool> ShowRelocatedSectionContents(
111 "show-relocated-section-contents",
112 cl::desc("show section contents after fixups have been applied"),
115 ExitOnError ExitOnErr
;
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)";
129 operator<<(raw_ostream
&OS
, const Session::SymbolInfoMap
&SIM
) {
131 for (auto &SKV
: SIM
)
132 OS
<< " \"" << SKV
.first() << "\" " << SKV
.second
<< "\n";
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";
148 operator<<(raw_ostream
&OS
, const Session::FileInfoMap
&FIM
) {
149 for (auto &FIKV
: FIM
)
150 OS
<< "File \"" << FIKV
.first() << "\":\n" << FIKV
.second
;
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();
160 TotalSize
+= DA
->getContent().size();
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())
177 if (LHS
->atoms_empty())
179 if (RHS
->atoms_empty())
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";
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
);
217 // Render the atom content.
218 while (NextAddr
!= AtomEnd
) {
219 if (NextAddr
% DumpWidth
== 0)
220 OS
<< formatv("\n{0:x16}:", NextAddr
);
224 OS
<< formatv(" {0:x-2}", AtomData
[NextAddr
- AtomStart
]);
232 class JITLinkSlabAllocator final
: public JITLinkMemoryManager
{
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
));
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
{
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();
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 "
297 inconvertibleErrorCode());
299 if (PageSize
% Seg
.getContentAlignment() != 0)
300 return make_error
<StringError
>("Page size is not a multiple of "
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
);
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
)));
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());
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
);
356 sys::Memory::allocateMappedMemory(SlabSize
, nullptr, ReadWrite
, EC
);
359 Err
= errorCodeToError(EC
);
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")) {
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
404 class JITLinkSessionPlugin
: public ObjectLinkingLayer::Plugin
{
406 JITLinkSessionPlugin(Session
&S
) : S(S
) {}
407 void modifyPassConfig(MaterializationResponsibility
&MR
, const Triple
&TT
,
408 PassConfiguration
&PassConfig
) {
409 S
.modifyPassConfig(TT
, PassConfig
);
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 "
435 inconvertibleErrorCode());
439 PassConfig
.PostFixupPasses
.push_back([](AtomGraph
&G
) -> Error
{
440 outs() << "Atom graph post-fixup:\n";
442 return Error::success();
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
);
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
+
483 inconvertibleErrorCode());
484 return SecInfoItr
->second
;
487 Expected
<Session::MemoryRegionInfo
&>
488 Session::findStubInfo(StringRef FileName
, StringRef TargetName
) {
489 auto FI
= findFileInfo(FileName
);
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
+
497 inconvertibleErrorCode());
498 return StubInfoItr
->second
;
501 Expected
<Session::MemoryRegionInfo
&>
502 Session::findGOTEntryInfo(StringRef FileName
, StringRef TargetName
) {
503 auto FI
= findFileInfo(FileName
);
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
+
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
+
525 inconvertibleErrorCode());
526 return SymInfoItr
->second
;
529 } // end namespace llvm
531 Triple
getFirstFileTriple() {
532 assert(!InputFiles
.empty() && "InputFiles can not be empty");
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";
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
) {
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();
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());
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
);
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
) {
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";);
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();
655 if (AddrStr
.getAsInteger(0, Addr
))
656 return make_error
<StringError
>("Invalid address expression \"" + AddrStr
+
657 "\" in absolute define \"" + AbsDefStmt
+
659 inconvertibleErrorCode());
660 JITEvaluatedSymbol
AbsDef(Addr
, JITSymbolFlags::Exported
);
661 if (auto Err
= JD
.define(absoluteSymbols({{S
.ES
.intern(Name
), AbsDef
}})))
664 // Register the absolute symbol with the session symbol infos.
665 S
.SymbolInfos
[Name
] = { StringRef(), Addr
};
669 dbgs() << "Dylib search order is [ ";
670 for (auto *JD
: S
.JDSearchOrder
)
671 dbgs() << JD
->getName() << " ";
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
);
684 ExitOnErr(make_error
<StringError
>("Error accessing target '" + TripleName
+
686 inconvertibleErrorCode()));
688 std::unique_ptr
<MCSubtargetInfo
> STI(
689 TheTarget
->createMCSubtargetInfo(TripleName
, "", ""));
692 make_error
<StringError
>("Unable to create subtarget for " + TripleName
,
693 inconvertibleErrorCode()));
695 std::unique_ptr
<MCRegisterInfo
> MRI(TheTarget
->createMCRegInfo(TripleName
));
697 ExitOnErr(make_error
<StringError
>("Unable to create target register info "
700 inconvertibleErrorCode()));
702 std::unique_ptr
<MCAsmInfo
> MAI(TheTarget
->createMCAsmInfo(*MRI
, TripleName
));
704 ExitOnErr(make_error
<StringError
>("Unable to create target asm info " +
706 inconvertibleErrorCode()));
708 MCContext
Ctx(MAI
.get(), MRI
.get(), nullptr);
710 std::unique_ptr
<MCDisassembler
> Disassembler(
711 TheTarget
->createMCDisassembler(*STI
, Ctx
));
713 ExitOnErr(make_error
<StringError
>("Unable to create disassembler for " +
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
) {
760 outs() << "Total size of all atoms before pruning: " << S
.SizeBeforePruning
761 << "\nTotal size of all atoms after fixups: " << S
.SizeAfterFixups
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
));
830 S
.dumpSessionInfo(outs());
832 ExitOnErr(runChecks(S
));
841 TimeRegion
TR(Timers
? &Timers
->RunTimer
: nullptr);
842 Result
= ExitOnErr(runEntryPoint(S
, EntryPoint
));