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> ShowLinkGraph(
91 cl::desc("Print the link 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 computeTotalBlockSizes(LinkGraph
&G
) {
155 uint64_t TotalSize
= 0;
156 for (auto *B
: G
.blocks())
157 TotalSize
+= B
->getSize();
161 static void dumpSectionContents(raw_ostream
&OS
, LinkGraph
&G
) {
162 constexpr JITTargetAddress DumpWidth
= 16;
163 static_assert(isPowerOf2_64(DumpWidth
), "DumpWidth must be a power of two");
165 // Put sections in address order.
166 std::vector
<Section
*> Sections
;
167 for (auto &S
: G
.sections())
168 Sections
.push_back(&S
);
170 std::sort(Sections
.begin(), Sections
.end(),
171 [](const Section
*LHS
, const Section
*RHS
) {
172 if (LHS
->symbols_empty() && RHS
->symbols_empty())
174 if (LHS
->symbols_empty())
176 if (RHS
->symbols_empty())
178 SectionRange
LHSRange(*LHS
);
179 SectionRange
RHSRange(*RHS
);
180 return LHSRange
.getStart() < RHSRange
.getStart();
183 for (auto *S
: Sections
) {
184 OS
<< S
->getName() << " content:";
185 if (S
->symbols_empty()) {
186 OS
<< "\n section empty\n";
190 // Sort symbols into order, then render.
191 std::vector
<Symbol
*> Syms(S
->symbols().begin(), S
->symbols().end());
192 llvm::sort(Syms
, [](const Symbol
*LHS
, const Symbol
*RHS
) {
193 return LHS
->getAddress() < RHS
->getAddress();
196 JITTargetAddress NextAddr
= Syms
.front()->getAddress() & ~(DumpWidth
- 1);
197 for (auto *Sym
: Syms
) {
198 bool IsZeroFill
= Sym
->getBlock().isZeroFill();
199 JITTargetAddress SymStart
= Sym
->getAddress();
200 JITTargetAddress SymSize
= Sym
->getSize();
201 JITTargetAddress SymEnd
= SymStart
+ SymSize
;
202 const uint8_t *SymData
=
203 IsZeroFill
? nullptr : Sym
->getSymbolContent().bytes_begin();
205 // Pad any space before the symbol starts.
206 while (NextAddr
!= SymStart
) {
207 if (NextAddr
% DumpWidth
== 0)
208 OS
<< formatv("\n{0:x16}:", NextAddr
);
213 // Render the symbol content.
214 while (NextAddr
!= SymEnd
) {
215 if (NextAddr
% DumpWidth
== 0)
216 OS
<< formatv("\n{0:x16}:", NextAddr
);
220 OS
<< formatv(" {0:x-2}", SymData
[NextAddr
- SymStart
]);
228 class JITLinkSlabAllocator final
: public JITLinkMemoryManager
{
230 static Expected
<std::unique_ptr
<JITLinkSlabAllocator
>>
231 Create(uint64_t SlabSize
) {
232 Error Err
= Error::success();
233 std::unique_ptr
<JITLinkSlabAllocator
> Allocator(
234 new JITLinkSlabAllocator(SlabSize
, Err
));
236 return std::move(Err
);
237 return std::move(Allocator
);
240 Expected
<std::unique_ptr
<JITLinkMemoryManager::Allocation
>>
241 allocate(const SegmentsRequestMap
&Request
) override
{
243 using AllocationMap
= DenseMap
<unsigned, sys::MemoryBlock
>;
245 // Local class for allocation.
246 class IPMMAlloc
: public Allocation
{
248 IPMMAlloc(AllocationMap SegBlocks
) : SegBlocks(std::move(SegBlocks
)) {}
249 MutableArrayRef
<char> getWorkingMemory(ProtectionFlags Seg
) override
{
250 assert(SegBlocks
.count(Seg
) && "No allocation for segment");
251 return {static_cast<char *>(SegBlocks
[Seg
].base()),
252 SegBlocks
[Seg
].allocatedSize()};
254 JITTargetAddress
getTargetMemory(ProtectionFlags Seg
) override
{
255 assert(SegBlocks
.count(Seg
) && "No allocation for segment");
256 return reinterpret_cast<JITTargetAddress
>(SegBlocks
[Seg
].base());
258 void finalizeAsync(FinalizeContinuation OnFinalize
) override
{
259 OnFinalize(applyProtections());
261 Error
deallocate() override
{
262 for (auto &KV
: SegBlocks
)
263 if (auto EC
= sys::Memory::releaseMappedMemory(KV
.second
))
264 return errorCodeToError(EC
);
265 return Error::success();
269 Error
applyProtections() {
270 for (auto &KV
: SegBlocks
) {
271 auto &Prot
= KV
.first
;
272 auto &Block
= KV
.second
;
273 if (auto EC
= sys::Memory::protectMappedMemory(Block
, Prot
))
274 return errorCodeToError(EC
);
275 if (Prot
& sys::Memory::MF_EXEC
)
276 sys::Memory::InvalidateInstructionCache(Block
.base(),
277 Block
.allocatedSize());
279 return Error::success();
282 AllocationMap SegBlocks
;
285 AllocationMap Blocks
;
287 for (auto &KV
: Request
) {
288 auto &Seg
= KV
.second
;
290 if (Seg
.getAlignment() > PageSize
)
291 return make_error
<StringError
>("Cannot request higher than page "
293 inconvertibleErrorCode());
295 if (PageSize
% Seg
.getAlignment() != 0)
296 return make_error
<StringError
>("Page size is not a multiple of "
298 inconvertibleErrorCode());
300 uint64_t ZeroFillStart
= Seg
.getContentSize();
301 uint64_t SegmentSize
= ZeroFillStart
+ Seg
.getZeroFillSize();
303 // Round segment size up to page boundary.
304 SegmentSize
= (SegmentSize
+ PageSize
- 1) & ~(PageSize
- 1);
306 // Take segment bytes from the front of the slab.
307 void *SlabBase
= SlabRemaining
.base();
308 uint64_t SlabRemainingSize
= SlabRemaining
.allocatedSize();
310 if (SegmentSize
> SlabRemainingSize
)
311 return make_error
<StringError
>("Slab allocator out of memory",
312 inconvertibleErrorCode());
314 sys::MemoryBlock
SegMem(SlabBase
, SegmentSize
);
316 sys::MemoryBlock(reinterpret_cast<char *>(SlabBase
) + SegmentSize
,
317 SlabRemainingSize
- SegmentSize
);
319 // Zero out the zero-fill memory.
320 memset(static_cast<char *>(SegMem
.base()) + ZeroFillStart
, 0,
321 Seg
.getZeroFillSize());
323 // Record the block for this segment.
324 Blocks
[KV
.first
] = std::move(SegMem
);
326 return std::unique_ptr
<InProcessMemoryManager::Allocation
>(
327 new IPMMAlloc(std::move(Blocks
)));
331 JITLinkSlabAllocator(uint64_t SlabSize
, Error
&Err
) {
332 ErrorAsOutParameter
_(&Err
);
334 PageSize
= sys::Process::getPageSizeEstimate();
336 if (!isPowerOf2_64(PageSize
)) {
337 Err
= make_error
<StringError
>("Page size is not a power of 2",
338 inconvertibleErrorCode());
342 // Round slab request up to page size.
343 SlabSize
= (SlabSize
+ PageSize
- 1) & ~(PageSize
- 1);
345 const sys::Memory::ProtectionFlags ReadWrite
=
346 static_cast<sys::Memory::ProtectionFlags
>(sys::Memory::MF_READ
|
347 sys::Memory::MF_WRITE
);
351 sys::Memory::allocateMappedMemory(SlabSize
, nullptr, ReadWrite
, EC
);
354 Err
= errorCodeToError(EC
);
359 sys::MemoryBlock SlabRemaining
;
360 uint64_t PageSize
= 0;
363 Expected
<uint64_t> getSlabAllocSize(StringRef SizeString
) {
364 SizeString
= SizeString
.trim();
366 uint64_t Units
= 1024;
368 if (SizeString
.endswith_lower("kb"))
369 SizeString
= SizeString
.drop_back(2).rtrim();
370 else if (SizeString
.endswith_lower("mb")) {
372 SizeString
= SizeString
.drop_back(2).rtrim();
373 } else if (SizeString
.endswith_lower("gb")) {
374 Units
= 1024 * 1024 * 1024;
375 SizeString
= SizeString
.drop_back(2).rtrim();
378 uint64_t SlabSize
= 0;
379 if (SizeString
.getAsInteger(10, SlabSize
))
380 return make_error
<StringError
>("Invalid numeric format for slab size",
381 inconvertibleErrorCode());
383 return SlabSize
* Units
;
386 static std::unique_ptr
<jitlink::JITLinkMemoryManager
> createMemoryManager() {
387 if (!SlabAllocateSizeString
.empty()) {
388 auto SlabSize
= ExitOnErr(getSlabAllocSize(SlabAllocateSizeString
));
389 return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize
));
391 return std::make_unique
<jitlink::InProcessMemoryManager
>();
394 Session::Session(Triple TT
)
395 : MemMgr(createMemoryManager()), ObjLayer(ES
, *MemMgr
), TT(std::move(TT
)) {
397 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
399 class JITLinkSessionPlugin
: public ObjectLinkingLayer::Plugin
{
401 JITLinkSessionPlugin(Session
&S
) : S(S
) {}
402 void modifyPassConfig(MaterializationResponsibility
&MR
, const Triple
&TT
,
403 PassConfiguration
&PassConfig
) {
404 S
.modifyPassConfig(TT
, PassConfig
);
411 if (!NoExec
&& !TT
.isOSWindows())
412 ObjLayer
.addPlugin(std::make_unique
<EHFrameRegistrationPlugin
>(
413 InProcessEHFrameRegistrar::getInstance()));
415 ObjLayer
.addPlugin(std::make_unique
<JITLinkSessionPlugin
>(*this));
418 void Session::dumpSessionInfo(raw_ostream
&OS
) {
419 OS
<< "Registered addresses:\n" << SymbolInfos
<< FileInfos
;
422 void Session::modifyPassConfig(const Triple
&FTT
,
423 PassConfiguration
&PassConfig
) {
424 if (!CheckFiles
.empty())
425 PassConfig
.PostFixupPasses
.push_back([this](LinkGraph
&G
) {
426 if (TT
.getObjectFormat() == Triple::MachO
)
427 return registerMachOStubsAndGOT(*this, G
);
428 return make_error
<StringError
>("Unsupported object format for GOT/stub "
430 inconvertibleErrorCode());
434 PassConfig
.PostFixupPasses
.push_back([](LinkGraph
&G
) -> Error
{
435 outs() << "Link graph post-fixup:\n";
437 return Error::success();
441 PassConfig
.PrePrunePasses
.push_back([this](LinkGraph
&G
) -> Error
{
442 SizeBeforePruning
+= computeTotalBlockSizes(G
);
443 return Error::success();
445 PassConfig
.PostFixupPasses
.push_back([this](LinkGraph
&G
) -> Error
{
446 SizeAfterFixups
+= computeTotalBlockSizes(G
);
447 return Error::success();
451 if (ShowRelocatedSectionContents
)
452 PassConfig
.PostFixupPasses
.push_back([](LinkGraph
&G
) -> Error
{
453 outs() << "Relocated section contents for " << G
.getName() << ":\n";
454 dumpSectionContents(outs(), G
);
455 return Error::success();
459 Expected
<Session::FileInfo
&> Session::findFileInfo(StringRef FileName
) {
460 auto FileInfoItr
= FileInfos
.find(FileName
);
461 if (FileInfoItr
== FileInfos
.end())
462 return make_error
<StringError
>("file \"" + FileName
+ "\" not recognized",
463 inconvertibleErrorCode());
464 return FileInfoItr
->second
;
467 Expected
<Session::MemoryRegionInfo
&>
468 Session::findSectionInfo(StringRef FileName
, StringRef SectionName
) {
469 auto FI
= findFileInfo(FileName
);
471 return FI
.takeError();
472 auto SecInfoItr
= FI
->SectionInfos
.find(SectionName
);
473 if (SecInfoItr
== FI
->SectionInfos
.end())
474 return make_error
<StringError
>("no section \"" + SectionName
+
475 "\" registered for file \"" + FileName
+
477 inconvertibleErrorCode());
478 return SecInfoItr
->second
;
481 Expected
<Session::MemoryRegionInfo
&>
482 Session::findStubInfo(StringRef FileName
, StringRef TargetName
) {
483 auto FI
= findFileInfo(FileName
);
485 return FI
.takeError();
486 auto StubInfoItr
= FI
->StubInfos
.find(TargetName
);
487 if (StubInfoItr
== FI
->StubInfos
.end())
488 return make_error
<StringError
>("no stub for \"" + TargetName
+
489 "\" registered for file \"" + FileName
+
491 inconvertibleErrorCode());
492 return StubInfoItr
->second
;
495 Expected
<Session::MemoryRegionInfo
&>
496 Session::findGOTEntryInfo(StringRef FileName
, StringRef TargetName
) {
497 auto FI
= findFileInfo(FileName
);
499 return FI
.takeError();
500 auto GOTInfoItr
= FI
->GOTEntryInfos
.find(TargetName
);
501 if (GOTInfoItr
== FI
->GOTEntryInfos
.end())
502 return make_error
<StringError
>("no GOT entry for \"" + TargetName
+
503 "\" registered for file \"" + FileName
+
505 inconvertibleErrorCode());
506 return GOTInfoItr
->second
;
509 bool Session::isSymbolRegistered(StringRef SymbolName
) {
510 return SymbolInfos
.count(SymbolName
);
513 Expected
<Session::MemoryRegionInfo
&>
514 Session::findSymbolInfo(StringRef SymbolName
, Twine ErrorMsgStem
) {
515 auto SymInfoItr
= SymbolInfos
.find(SymbolName
);
516 if (SymInfoItr
== SymbolInfos
.end())
517 return make_error
<StringError
>(ErrorMsgStem
+ ": symbol " + SymbolName
+
519 inconvertibleErrorCode());
520 return SymInfoItr
->second
;
523 } // end namespace llvm
525 Triple
getFirstFileTriple() {
526 assert(!InputFiles
.empty() && "InputFiles can not be empty");
528 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles
.front())));
529 auto Obj
= ExitOnErr(
530 object::ObjectFile::createObjectFile(ObjBuffer
->getMemBufferRef()));
531 return Obj
->makeTriple();
534 Error
sanitizeArguments(const Session
&S
) {
535 if (EntryPointName
.empty()) {
536 if (S
.TT
.getObjectFormat() == Triple::MachO
)
537 EntryPointName
= "_main";
539 EntryPointName
= "main";
542 if (NoExec
&& !InputArgv
.empty())
543 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
545 return Error::success();
548 Error
loadProcessSymbols(Session
&S
) {
550 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg
))
551 return make_error
<StringError
>(std::move(ErrMsg
), inconvertibleErrorCode());
553 char GlobalPrefix
= S
.TT
.getObjectFormat() == Triple::MachO
? '_' : '\0';
554 auto InternedEntryPointName
= S
.ES
.intern(EntryPointName
);
555 auto FilterMainEntryPoint
= [InternedEntryPointName
](SymbolStringPtr Name
) {
556 return Name
!= InternedEntryPointName
;
558 S
.ES
.getMainJITDylib().addGenerator(
559 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
560 GlobalPrefix
, FilterMainEntryPoint
)));
562 return Error::success();
566 // FIXME: This should all be handled inside DynamicLibrary.
567 for (const auto &Dylib
: Dylibs
) {
568 if (!sys::fs::is_regular_file(Dylib
))
569 return make_error
<StringError
>("\"" + Dylib
+ "\" is not a regular file",
570 inconvertibleErrorCode());
572 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib
.c_str(), &ErrMsg
))
573 return make_error
<StringError
>(ErrMsg
, inconvertibleErrorCode());
576 return Error::success();
579 Error
loadObjects(Session
&S
) {
581 std::map
<unsigned, JITDylib
*> IdxToJLD
;
583 // First, set up JITDylibs.
584 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
586 // Create a "main" JITLinkDylib.
587 auto &MainJD
= S
.ES
.getMainJITDylib();
588 IdxToJLD
[0] = &MainJD
;
589 S
.JDSearchOrder
.push_back(&MainJD
);
590 LLVM_DEBUG(dbgs() << " 0: " << MainJD
.getName() << "\n");
592 // Add any extra JITLinkDylibs from the command line.
593 std::string
JDNamePrefix("lib");
594 for (auto JLDItr
= JITLinkDylibs
.begin(), JLDEnd
= JITLinkDylibs
.end();
595 JLDItr
!= JLDEnd
; ++JLDItr
) {
596 auto &JD
= S
.ES
.createJITDylib(JDNamePrefix
+ *JLDItr
);
598 JITLinkDylibs
.getPosition(JLDItr
- JITLinkDylibs
.begin());
599 IdxToJLD
[JDIdx
] = &JD
;
600 S
.JDSearchOrder
.push_back(&JD
);
601 LLVM_DEBUG(dbgs() << " " << JDIdx
<< ": " << JD
.getName() << "\n");
604 // Set every dylib to link against every other, in command line order.
605 for (auto *JD
: S
.JDSearchOrder
) {
606 JITDylibSearchList O
;
607 for (auto *JD2
: S
.JDSearchOrder
) {
610 O
.push_back(std::make_pair(JD2
, false));
612 JD
->setSearchOrder(std::move(O
));
616 // Load each object into the corresponding JITDylib..
617 LLVM_DEBUG(dbgs() << "Adding objects...\n");
618 for (auto InputFileItr
= InputFiles
.begin(), InputFileEnd
= InputFiles
.end();
619 InputFileItr
!= InputFileEnd
; ++InputFileItr
) {
620 unsigned InputFileArgIdx
=
621 InputFiles
.getPosition(InputFileItr
- InputFiles
.begin());
622 StringRef InputFile
= *InputFileItr
;
623 auto &JD
= *std::prev(IdxToJLD
.lower_bound(InputFileArgIdx
))->second
;
624 LLVM_DEBUG(dbgs() << " " << InputFileArgIdx
<< ": \"" << InputFile
625 << "\" to " << JD
.getName() << "\n";);
627 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile
)));
628 ExitOnErr(S
.ObjLayer
.add(JD
, std::move(ObjBuffer
)));
631 // Define absolute symbols.
632 LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n");
633 for (auto AbsDefItr
= AbsoluteDefs
.begin(), AbsDefEnd
= AbsoluteDefs
.end();
634 AbsDefItr
!= AbsDefEnd
; ++AbsDefItr
) {
635 unsigned AbsDefArgIdx
=
636 AbsoluteDefs
.getPosition(AbsDefItr
- AbsoluteDefs
.begin());
637 auto &JD
= *std::prev(IdxToJLD
.lower_bound(AbsDefArgIdx
))->second
;
639 StringRef AbsDefStmt
= *AbsDefItr
;
640 size_t EqIdx
= AbsDefStmt
.find_first_of('=');
641 if (EqIdx
== StringRef::npos
)
642 return make_error
<StringError
>("Invalid absolute define \"" + AbsDefStmt
+
643 "\". Syntax: <name>=<addr>",
644 inconvertibleErrorCode());
645 StringRef Name
= AbsDefStmt
.substr(0, EqIdx
).trim();
646 StringRef AddrStr
= AbsDefStmt
.substr(EqIdx
+ 1).trim();
649 if (AddrStr
.getAsInteger(0, Addr
))
650 return make_error
<StringError
>("Invalid address expression \"" + AddrStr
+
651 "\" in absolute define \"" + AbsDefStmt
+
653 inconvertibleErrorCode());
654 JITEvaluatedSymbol
AbsDef(Addr
, JITSymbolFlags::Exported
);
655 if (auto Err
= JD
.define(absoluteSymbols({{S
.ES
.intern(Name
), AbsDef
}})))
658 // Register the absolute symbol with the session symbol infos.
659 S
.SymbolInfos
[Name
] = { StringRef(), Addr
};
663 dbgs() << "Dylib search order is [ ";
664 for (auto *JD
: S
.JDSearchOrder
)
665 dbgs() << JD
->getName() << " ";
669 return Error::success();
672 Error
runChecks(Session
&S
) {
674 auto TripleName
= S
.TT
.str();
675 std::string ErrorStr
;
676 const Target
*TheTarget
= TargetRegistry::lookupTarget("", S
.TT
, ErrorStr
);
678 ExitOnErr(make_error
<StringError
>("Error accessing target '" + TripleName
+
680 inconvertibleErrorCode()));
682 std::unique_ptr
<MCSubtargetInfo
> STI(
683 TheTarget
->createMCSubtargetInfo(TripleName
, "", ""));
686 make_error
<StringError
>("Unable to create subtarget for " + TripleName
,
687 inconvertibleErrorCode()));
689 std::unique_ptr
<MCRegisterInfo
> MRI(TheTarget
->createMCRegInfo(TripleName
));
691 ExitOnErr(make_error
<StringError
>("Unable to create target register info "
694 inconvertibleErrorCode()));
696 std::unique_ptr
<MCAsmInfo
> MAI(TheTarget
->createMCAsmInfo(*MRI
, TripleName
));
698 ExitOnErr(make_error
<StringError
>("Unable to create target asm info " +
700 inconvertibleErrorCode()));
702 MCContext
Ctx(MAI
.get(), MRI
.get(), nullptr);
704 std::unique_ptr
<MCDisassembler
> Disassembler(
705 TheTarget
->createMCDisassembler(*STI
, Ctx
));
707 ExitOnErr(make_error
<StringError
>("Unable to create disassembler for " +
709 inconvertibleErrorCode()));
711 std::unique_ptr
<MCInstrInfo
> MII(TheTarget
->createMCInstrInfo());
713 std::unique_ptr
<MCInstPrinter
> InstPrinter(
714 TheTarget
->createMCInstPrinter(Triple(TripleName
), 0, *MAI
, *MII
, *MRI
));
716 auto IsSymbolValid
= [&S
](StringRef Symbol
) {
717 return S
.isSymbolRegistered(Symbol
);
720 auto GetSymbolInfo
= [&S
](StringRef Symbol
) {
721 return S
.findSymbolInfo(Symbol
, "Can not get symbol info");
724 auto GetSectionInfo
= [&S
](StringRef FileName
, StringRef SectionName
) {
725 return S
.findSectionInfo(FileName
, SectionName
);
728 auto GetStubInfo
= [&S
](StringRef FileName
, StringRef SectionName
) {
729 return S
.findStubInfo(FileName
, SectionName
);
732 auto GetGOTInfo
= [&S
](StringRef FileName
, StringRef SectionName
) {
733 return S
.findGOTEntryInfo(FileName
, SectionName
);
736 RuntimeDyldChecker
Checker(
737 IsSymbolValid
, GetSymbolInfo
, GetSectionInfo
, GetStubInfo
, GetGOTInfo
,
738 S
.TT
.isLittleEndian() ? support::little
: support::big
,
739 Disassembler
.get(), InstPrinter
.get(), dbgs());
741 for (auto &CheckFile
: CheckFiles
) {
742 auto CheckerFileBuf
=
743 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile
)));
744 if (!Checker
.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf
))
745 ExitOnErr(make_error
<StringError
>(
746 "Some checks in " + CheckFile
+ " failed", inconvertibleErrorCode()));
749 return Error::success();
752 static void dumpSessionStats(Session
&S
) {
754 outs() << "Total size of all blocks before pruning: " << S
.SizeBeforePruning
755 << "\nTotal size of all blocks after fixups: " << S
.SizeAfterFixups
759 static Expected
<JITEvaluatedSymbol
> getMainEntryPoint(Session
&S
) {
760 return S
.ES
.lookup(S
.JDSearchOrder
, EntryPointName
);
763 Expected
<int> runEntryPoint(Session
&S
, JITEvaluatedSymbol EntryPoint
) {
764 assert(EntryPoint
.getAddress() && "Entry point address should not be null");
766 constexpr const char *JITProgramName
= "<llvm-jitlink jit'd code>";
767 auto PNStorage
= std::make_unique
<char[]>(strlen(JITProgramName
) + 1);
768 strcpy(PNStorage
.get(), JITProgramName
);
770 std::vector
<const char *> EntryPointArgs
;
771 EntryPointArgs
.push_back(PNStorage
.get());
772 for (auto &InputArg
: InputArgv
)
773 EntryPointArgs
.push_back(InputArg
.data());
774 EntryPointArgs
.push_back(nullptr);
776 using MainTy
= int (*)(int, const char *[]);
777 MainTy EntryPointPtr
= reinterpret_cast<MainTy
>(EntryPoint
.getAddress());
779 return EntryPointPtr(EntryPointArgs
.size() - 1, EntryPointArgs
.data());
782 struct JITLinkTimers
{
783 TimerGroup JITLinkTG
{"llvm-jitlink timers", "timers for llvm-jitlink phases"};
784 Timer LoadObjectsTimer
{"load", "time to load/add object files", JITLinkTG
};
785 Timer LinkTimer
{"link", "time to link object files", JITLinkTG
};
786 Timer RunTimer
{"run", "time to execute jitlink'd code", JITLinkTG
};
789 int main(int argc
, char *argv
[]) {
790 InitLLVM
X(argc
, argv
);
792 InitializeAllTargetInfos();
793 InitializeAllTargetMCs();
794 InitializeAllDisassemblers();
796 cl::ParseCommandLineOptions(argc
, argv
, "llvm jitlink tool");
797 ExitOnErr
.setBanner(std::string(argv
[0]) + ": ");
799 /// If timers are enabled, create a JITLinkTimers instance.
800 std::unique_ptr
<JITLinkTimers
> Timers
=
801 ShowTimes
? std::make_unique
<JITLinkTimers
>() : nullptr;
803 Session
S(getFirstFileTriple());
805 ExitOnErr(sanitizeArguments(S
));
807 if (!NoProcessSymbols
)
808 ExitOnErr(loadProcessSymbols(S
));
809 ExitOnErr(loadDylibs());
813 TimeRegion
TR(Timers
? &Timers
->LoadObjectsTimer
: nullptr);
814 ExitOnErr(loadObjects(S
));
817 JITEvaluatedSymbol EntryPoint
= 0;
819 TimeRegion
TR(Timers
? &Timers
->LinkTimer
: nullptr);
820 EntryPoint
= ExitOnErr(getMainEntryPoint(S
));
824 S
.dumpSessionInfo(outs());
826 ExitOnErr(runChecks(S
));
835 TimeRegion
TR(Timers
? &Timers
->RunTimer
: nullptr);
836 Result
= ExitOnErr(runEntryPoint(S
, EntryPoint
));