blob: 26bcf46d60a6f7311850de0cb958ec127a972e15 [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"
Mirko Brkusanin4b63ca12019-10-23 12:24:35 +020026#include "llvm/MC/MCTargetOptions.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000027#include "llvm/Object/COFF.h"
28#include "llvm/Object/MachO.h"
29#include "llvm/Object/ObjectFile.h"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/Debug.h"
32#include "llvm/Support/DynamicLibrary.h"
33#include "llvm/Support/InitLLVM.h"
34#include "llvm/Support/MemoryBuffer.h"
Lang Hames335676e2019-09-06 19:21:55 +000035#include "llvm/Support/Process.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000036#include "llvm/Support/TargetRegistry.h"
37#include "llvm/Support/TargetSelect.h"
Lang Hames6fd39602019-08-27 15:51:19 +000038#include "llvm/Support/Timer.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000039
40#include <list>
41#include <string>
42
Lang Hames11c8dfa52019-04-20 17:10:34 +000043#define DEBUG_TYPE "llvm-jitlink"
44
45using namespace llvm;
46using namespace llvm::jitlink;
47using namespace llvm::orc;
48
49static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
50 cl::desc("input files"));
51
52static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
53 cl::init(false));
54
55static cl::list<std::string>
56 CheckFiles("check", cl::desc("File containing verifier checks"),
57 cl::ZeroOrMore);
58
59static cl::opt<std::string>
Lang Hames674df132019-11-25 21:57:27 -080060 CheckName("check-name", cl::desc("Name of checks to match against"),
61 cl::init("jitlink-check"));
62
63static cl::opt<std::string>
Lang Hames11c8dfa52019-04-20 17:10:34 +000064 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
65 cl::init(""));
66
67static cl::list<std::string> JITLinkDylibs(
68 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
69 "input file arguments"));
70
71static cl::list<std::string>
72 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
73 cl::ZeroOrMore);
74
Lang Hamesd959a602019-04-24 17:23:05 +000075static cl::list<std::string> InputArgv("args", cl::Positional,
76 cl::desc("<program arguments>..."),
77 cl::ZeroOrMore, cl::PositionalEatsArgs);
78
Lang Hames11c8dfa52019-04-20 17:10:34 +000079static cl::opt<bool>
80 NoProcessSymbols("no-process-syms",
81 cl::desc("Do not resolve to llvm-jitlink process symbols"),
82 cl::init(false));
83
Nico Weber405e62b2019-04-21 23:50:24 +000084static cl::list<std::string> AbsoluteDefs(
85 "define-abs",
86 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
87 cl::ZeroOrMore);
Lang Hames11c8dfa52019-04-20 17:10:34 +000088
89static cl::opt<bool> ShowAddrs(
90 "show-addrs",
91 cl::desc("Print registered symbol, section, got and stub addresses"),
92 cl::init(false));
93
Lang Hames4e920e52019-10-04 03:55:26 +000094static cl::opt<bool> ShowLinkGraph(
Lang Hames11c8dfa52019-04-20 17:10:34 +000095 "show-graph",
Lang Hames4e920e52019-10-04 03:55:26 +000096 cl::desc("Print the link graph after fixups have been applied"),
Lang Hames11c8dfa52019-04-20 17:10:34 +000097 cl::init(false));
98
99static cl::opt<bool> ShowSizes(
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000100 "show-sizes",
101 cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
102 cl::init(false));
103
Lang Hames6fd39602019-08-27 15:51:19 +0000104static cl::opt<bool> ShowTimes("show-times",
105 cl::desc("Show times for llvm-jitlink phases"),
106 cl::init(false));
107
Lang Hames335676e2019-09-06 19:21:55 +0000108static cl::opt<std::string> SlabAllocateSizeString(
109 "slab-allocate",
110 cl::desc("Allocate from a slab of the given size "
111 "(allowable suffixes: Kb, Mb, Gb. default = "
112 "Kb)"),
113 cl::init(""));
114
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000115static cl::opt<bool> ShowRelocatedSectionContents(
116 "show-relocated-section-contents",
117 cl::desc("show section contents after fixups have been applied"),
118 cl::init(false));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000119
120ExitOnError ExitOnErr;
121
122namespace llvm {
123
124static raw_ostream &
125operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
Lang Hames23085ec2019-05-12 22:26:33 +0000126 return OS << "target addr = "
127 << format("0x%016" PRIx64, MRI.getTargetAddress())
128 << ", content: " << (const void *)MRI.getContent().data() << " -- "
129 << (const void *)(MRI.getContent().data() + MRI.getContent().size())
130 << " (" << MRI.getContent().size() << " bytes)";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000131}
132
133static raw_ostream &
134operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) {
135 OS << "Symbols:\n";
136 for (auto &SKV : SIM)
137 OS << " \"" << SKV.first() << "\" " << SKV.second << "\n";
138 return OS;
139}
140
141static raw_ostream &
142operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
143 for (auto &SIKV : FI.SectionInfos)
144 OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
145 for (auto &GOTKV : FI.GOTEntryInfos)
146 OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
147 for (auto &StubKV : FI.StubInfos)
148 OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
149 return OS;
150}
151
152static raw_ostream &
153operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) {
154 for (auto &FIKV : FIM)
155 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second;
156 return OS;
157}
158
Lang Hames4e920e52019-10-04 03:55:26 +0000159static uint64_t computeTotalBlockSizes(LinkGraph &G) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000160 uint64_t TotalSize = 0;
Lang Hames4e920e52019-10-04 03:55:26 +0000161 for (auto *B : G.blocks())
162 TotalSize += B->getSize();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000163 return TotalSize;
164}
165
Lang Hames4e920e52019-10-04 03:55:26 +0000166static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000167 constexpr JITTargetAddress DumpWidth = 16;
168 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two");
169
170 // Put sections in address order.
171 std::vector<Section *> Sections;
172 for (auto &S : G.sections())
173 Sections.push_back(&S);
174
175 std::sort(Sections.begin(), Sections.end(),
176 [](const Section *LHS, const Section *RHS) {
Lang Hames8c4f0482019-12-05 19:57:51 -0800177 if (llvm::empty(LHS->symbols()) && llvm::empty(RHS->symbols()))
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000178 return false;
Lang Hames8c4f0482019-12-05 19:57:51 -0800179 if (llvm::empty(LHS->symbols()))
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000180 return false;
Lang Hames8c4f0482019-12-05 19:57:51 -0800181 if (llvm::empty(RHS->symbols()))
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000182 return true;
Lang Hames4e920e52019-10-04 03:55:26 +0000183 SectionRange LHSRange(*LHS);
184 SectionRange RHSRange(*RHS);
185 return LHSRange.getStart() < RHSRange.getStart();
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000186 });
187
188 for (auto *S : Sections) {
189 OS << S->getName() << " content:";
Lang Hames8c4f0482019-12-05 19:57:51 -0800190 if (llvm::empty(S->symbols())) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000191 OS << "\n section empty\n";
192 continue;
193 }
194
Lang Hames4e920e52019-10-04 03:55:26 +0000195 // Sort symbols into order, then render.
196 std::vector<Symbol *> Syms(S->symbols().begin(), S->symbols().end());
197 llvm::sort(Syms, [](const Symbol *LHS, const Symbol *RHS) {
198 return LHS->getAddress() < RHS->getAddress();
199 });
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000200
Lang Hames4e920e52019-10-04 03:55:26 +0000201 JITTargetAddress NextAddr = Syms.front()->getAddress() & ~(DumpWidth - 1);
202 for (auto *Sym : Syms) {
203 bool IsZeroFill = Sym->getBlock().isZeroFill();
204 JITTargetAddress SymStart = Sym->getAddress();
205 JITTargetAddress SymSize = Sym->getSize();
206 JITTargetAddress SymEnd = SymStart + SymSize;
207 const uint8_t *SymData =
208 IsZeroFill ? nullptr : Sym->getSymbolContent().bytes_begin();
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000209
Lang Hames4e920e52019-10-04 03:55:26 +0000210 // Pad any space before the symbol starts.
211 while (NextAddr != SymStart) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000212 if (NextAddr % DumpWidth == 0)
213 OS << formatv("\n{0:x16}:", NextAddr);
214 OS << " ";
215 ++NextAddr;
216 }
217
Lang Hames4e920e52019-10-04 03:55:26 +0000218 // Render the symbol content.
219 while (NextAddr != SymEnd) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000220 if (NextAddr % DumpWidth == 0)
221 OS << formatv("\n{0:x16}:", NextAddr);
222 if (IsZeroFill)
223 OS << " 00";
224 else
Lang Hames4e920e52019-10-04 03:55:26 +0000225 OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]);
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000226 ++NextAddr;
227 }
228 }
229 OS << "\n";
230 }
231}
232
Lang Hames335676e2019-09-06 19:21:55 +0000233class JITLinkSlabAllocator final : public JITLinkMemoryManager {
234public:
235 static Expected<std::unique_ptr<JITLinkSlabAllocator>>
236 Create(uint64_t SlabSize) {
237 Error Err = Error::success();
238 std::unique_ptr<JITLinkSlabAllocator> Allocator(
239 new JITLinkSlabAllocator(SlabSize, Err));
240 if (Err)
Bill Wendlingc55cf4a2020-02-10 07:06:45 -0800241 return std::move(Err);
242 return std::move(Allocator);
Lang Hames335676e2019-09-06 19:21:55 +0000243 }
244
245 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
246 allocate(const SegmentsRequestMap &Request) override {
247
248 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
249
250 // Local class for allocation.
251 class IPMMAlloc : public Allocation {
252 public:
253 IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
254 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
255 assert(SegBlocks.count(Seg) && "No allocation for segment");
256 return {static_cast<char *>(SegBlocks[Seg].base()),
257 SegBlocks[Seg].allocatedSize()};
258 }
259 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
260 assert(SegBlocks.count(Seg) && "No allocation for segment");
261 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
262 }
263 void finalizeAsync(FinalizeContinuation OnFinalize) override {
264 OnFinalize(applyProtections());
265 }
266 Error deallocate() override {
267 for (auto &KV : SegBlocks)
268 if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
269 return errorCodeToError(EC);
270 return Error::success();
271 }
272
273 private:
274 Error applyProtections() {
275 for (auto &KV : SegBlocks) {
276 auto &Prot = KV.first;
277 auto &Block = KV.second;
278 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
279 return errorCodeToError(EC);
280 if (Prot & sys::Memory::MF_EXEC)
281 sys::Memory::InvalidateInstructionCache(Block.base(),
282 Block.allocatedSize());
283 }
284 return Error::success();
285 }
286
287 AllocationMap SegBlocks;
288 };
289
290 AllocationMap Blocks;
291
292 for (auto &KV : Request) {
293 auto &Seg = KV.second;
294
Lang Hames4e920e52019-10-04 03:55:26 +0000295 if (Seg.getAlignment() > PageSize)
Lang Hames335676e2019-09-06 19:21:55 +0000296 return make_error<StringError>("Cannot request higher than page "
297 "alignment",
298 inconvertibleErrorCode());
299
Lang Hames4e920e52019-10-04 03:55:26 +0000300 if (PageSize % Seg.getAlignment() != 0)
Lang Hames335676e2019-09-06 19:21:55 +0000301 return make_error<StringError>("Page size is not a multiple of "
302 "alignment",
303 inconvertibleErrorCode());
304
Lang Hames4e920e52019-10-04 03:55:26 +0000305 uint64_t ZeroFillStart = Seg.getContentSize();
Lang Hames335676e2019-09-06 19:21:55 +0000306 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
307
308 // Round segment size up to page boundary.
309 SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1);
310
311 // Take segment bytes from the front of the slab.
312 void *SlabBase = SlabRemaining.base();
313 uint64_t SlabRemainingSize = SlabRemaining.allocatedSize();
314
315 if (SegmentSize > SlabRemainingSize)
316 return make_error<StringError>("Slab allocator out of memory",
317 inconvertibleErrorCode());
318
319 sys::MemoryBlock SegMem(SlabBase, SegmentSize);
320 SlabRemaining =
321 sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize,
322 SlabRemainingSize - SegmentSize);
323
324 // Zero out the zero-fill memory.
325 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
326 Seg.getZeroFillSize());
327
328 // Record the block for this segment.
329 Blocks[KV.first] = std::move(SegMem);
330 }
331 return std::unique_ptr<InProcessMemoryManager::Allocation>(
332 new IPMMAlloc(std::move(Blocks)));
333 }
334
335private:
336 JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
337 ErrorAsOutParameter _(&Err);
338
339 PageSize = sys::Process::getPageSizeEstimate();
340
341 if (!isPowerOf2_64(PageSize)) {
342 Err = make_error<StringError>("Page size is not a power of 2",
343 inconvertibleErrorCode());
344 return;
345 }
346
347 // Round slab request up to page size.
348 SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
349
350 const sys::Memory::ProtectionFlags ReadWrite =
351 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
352 sys::Memory::MF_WRITE);
353
354 std::error_code EC;
355 SlabRemaining =
356 sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
357
358 if (EC) {
359 Err = errorCodeToError(EC);
360 return;
361 }
362 }
363
364 sys::MemoryBlock SlabRemaining;
365 uint64_t PageSize = 0;
366};
367
368Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
369 SizeString = SizeString.trim();
370
371 uint64_t Units = 1024;
372
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();
381 }
382
383 uint64_t SlabSize = 0;
384 if (SizeString.getAsInteger(10, SlabSize))
385 return make_error<StringError>("Invalid numeric format for slab size",
386 inconvertibleErrorCode());
387
388 return SlabSize * Units;
389}
390
391static std::unique_ptr<jitlink::JITLinkMemoryManager> createMemoryManager() {
392 if (!SlabAllocateSizeString.empty()) {
393 auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
394 return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
395 }
396 return std::make_unique<jitlink::InProcessMemoryManager>();
397}
398
399Session::Session(Triple TT)
Lang Hamesc0143f32019-12-15 17:23:36 -0800400 : MainJD(ES.createJITDylib("<main>")), ObjLayer(ES, createMemoryManager()),
401 TT(std::move(TT)) {
Lang Hamesa9fdf372019-04-26 22:58:39 +0000402
403 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
404 /// Session.
405 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
406 public:
407 JITLinkSessionPlugin(Session &S) : S(S) {}
408 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
409 PassConfiguration &PassConfig) {
410 S.modifyPassConfig(TT, PassConfig);
411 }
412
413 private:
414 Session &S;
415 };
416
417 if (!NoExec && !TT.isOSWindows())
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000418 ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
Lang Hamesf5a885f2019-07-04 00:05:12 +0000419 InProcessEHFrameRegistrar::getInstance()));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000420
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000421 ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000422}
Lang Hames11c8dfa52019-04-20 17:10:34 +0000423
424void Session::dumpSessionInfo(raw_ostream &OS) {
425 OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
426}
427
428void Session::modifyPassConfig(const Triple &FTT,
429 PassConfiguration &PassConfig) {
430 if (!CheckFiles.empty())
Lang Hames4e920e52019-10-04 03:55:26 +0000431 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000432 if (TT.getObjectFormat() == Triple::MachO)
433 return registerMachOStubsAndGOT(*this, G);
434 return make_error<StringError>("Unsupported object format for GOT/stub "
435 "registration",
436 inconvertibleErrorCode());
437 });
438
Lang Hames4e920e52019-10-04 03:55:26 +0000439 if (ShowLinkGraph)
440 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
441 outs() << "Link graph post-fixup:\n";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000442 G.dump(outs());
443 return Error::success();
444 });
445
Lang Hames11c8dfa52019-04-20 17:10:34 +0000446 if (ShowSizes) {
Lang Hames4e920e52019-10-04 03:55:26 +0000447 PassConfig.PrePrunePasses.push_back([this](LinkGraph &G) -> Error {
448 SizeBeforePruning += computeTotalBlockSizes(G);
449 return Error::success();
450 });
451 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) -> Error {
452 SizeAfterFixups += computeTotalBlockSizes(G);
453 return Error::success();
454 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000455 }
456
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000457 if (ShowRelocatedSectionContents)
Lang Hames4e920e52019-10-04 03:55:26 +0000458 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000459 outs() << "Relocated section contents for " << G.getName() << ":\n";
460 dumpSectionContents(outs(), G);
461 return Error::success();
462 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000463}
464
465Expected<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;
471}
472
473Expected<Session::MemoryRegionInfo &>
474Session::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;
485}
486
487Expected<Session::MemoryRegionInfo &>
488Session::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;
499}
500
501Expected<Session::MemoryRegionInfo &>
502Session::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;
513}
514
515bool Session::isSymbolRegistered(StringRef SymbolName) {
516 return SymbolInfos.count(SymbolName);
517}
518
519Expected<Session::MemoryRegionInfo &>
520Session::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;
527}
528
529} // end namespace llvm
530
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000531Triple 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();
538}
539
Lang Hamesd959a602019-04-24 17:23:05 +0000540Error sanitizeArguments(const Session &S) {
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000541 if (EntryPointName.empty()) {
542 if (S.TT.getObjectFormat() == Triple::MachO)
543 EntryPointName = "_main";
544 else
545 EntryPointName = "main";
546 }
Lang Hamesd959a602019-04-24 17:23:05 +0000547
548 if (NoExec && !InputArgv.empty())
549 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
550
551 return Error::success();
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000552}
553
Lang Hames11c8dfa52019-04-20 17:10:34 +0000554Error loadProcessSymbols(Session &S) {
555 std::string ErrMsg;
556 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg))
557 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
558
559 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0';
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000560 auto InternedEntryPointName = S.ES.intern(EntryPointName);
561 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
562 return Name != InternedEntryPointName;
563 };
Lang Hames4fc68b92019-12-04 22:45:38 -0800564 S.MainJD.addGenerator(
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000565 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
566 GlobalPrefix, FilterMainEntryPoint)));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000567
568 return Error::success();
569}
570
571Error 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());
580 }
581
582 return Error::success();
583}
584
Lang Hames11c8dfa52019-04-20 17:10:34 +0000585Error loadObjects(Session &S) {
586
587 std::map<unsigned, JITDylib *> IdxToJLD;
588
589 // First, set up JITDylibs.
590 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
591 {
592 // Create a "main" JITLinkDylib.
Lang Hames4fc68b92019-12-04 22:45:38 -0800593 IdxToJLD[0] = &S.MainJD;
594 S.JDSearchOrder.push_back(&S.MainJD);
595 LLVM_DEBUG(dbgs() << " 0: " << S.MainJD.getName() << "\n");
Lang Hames11c8dfa52019-04-20 17:10:34 +0000596
597 // Add any extra JITLinkDylibs from the command line.
598 std::string JDNamePrefix("lib");
599 for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end();
600 JLDItr != JLDEnd; ++JLDItr) {
601 auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr);
602 unsigned JDIdx =
603 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin());
604 IdxToJLD[JDIdx] = &JD;
605 S.JDSearchOrder.push_back(&JD);
606 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n");
607 }
608
609 // Set every dylib to link against every other, in command line order.
610 for (auto *JD : S.JDSearchOrder) {
Lang Hames674df132019-11-25 21:57:27 -0800611 auto LookupFlags = JITDylibLookupFlags::MatchExportedSymbolsOnly;
612 JITDylibSearchOrder O;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000613 for (auto *JD2 : S.JDSearchOrder) {
614 if (JD2 == JD)
615 continue;
Lang Hames674df132019-11-25 21:57:27 -0800616 O.push_back(std::make_pair(JD2, LookupFlags));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000617 }
618 JD->setSearchOrder(std::move(O));
619 }
620 }
621
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)));
635 }
636
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;
644
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();
653
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;
663
664 // Register the absolute symbol with the session symbol infos.
665 S.SymbolInfos[Name] = { StringRef(), Addr };
666 }
667
668 LLVM_DEBUG({
669 dbgs() << "Dylib search order is [ ";
670 for (auto *JD : S.JDSearchOrder)
671 dbgs() << JD->getName() << " ";
672 dbgs() << "]\n";
673 });
674
675 return Error::success();
676}
677
678Error runChecks(Session &S) {
679
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()));
687
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()));
694
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()));
701
Mirko Brkusanin4b63ca12019-10-23 12:24:35 +0200702 MCTargetOptions MCOptions;
703 std::unique_ptr<MCAsmInfo> MAI(
704 TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000705 if (!MAI)
706 ExitOnErr(make_error<StringError>("Unable to create target asm info " +
707 TripleName,
708 inconvertibleErrorCode()));
709
710 MCContext Ctx(MAI.get(), MRI.get(), nullptr);
711
712 std::unique_ptr<MCDisassembler> Disassembler(
713 TheTarget->createMCDisassembler(*STI, Ctx));
714 if (!Disassembler)
715 ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
716 TripleName,
717 inconvertibleErrorCode()));
718
719 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
720
721 std::unique_ptr<MCInstPrinter> InstPrinter(
722 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
723
724 auto IsSymbolValid = [&S](StringRef Symbol) {
725 return S.isSymbolRegistered(Symbol);
726 };
727
728 auto GetSymbolInfo = [&S](StringRef Symbol) {
729 return S.findSymbolInfo(Symbol, "Can not get symbol info");
730 };
731
732 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
733 return S.findSectionInfo(FileName, SectionName);
734 };
735
736 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
737 return S.findStubInfo(FileName, SectionName);
738 };
739
740 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
741 return S.findGOTEntryInfo(FileName, SectionName);
742 };
743
744 RuntimeDyldChecker Checker(
745 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
746 S.TT.isLittleEndian() ? support::little : support::big,
747 Disassembler.get(), InstPrinter.get(), dbgs());
748
Lang Hames674df132019-11-25 21:57:27 -0800749 std::string CheckLineStart = "# " + CheckName + ":";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000750 for (auto &CheckFile : CheckFiles) {
751 auto CheckerFileBuf =
752 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile)));
Lang Hames674df132019-11-25 21:57:27 -0800753 if (!Checker.checkAllRulesInBuffer(CheckLineStart, &*CheckerFileBuf))
Lang Hames11c8dfa52019-04-20 17:10:34 +0000754 ExitOnErr(make_error<StringError>(
755 "Some checks in " + CheckFile + " failed", inconvertibleErrorCode()));
756 }
757
758 return Error::success();
759}
760
761static void dumpSessionStats(Session &S) {
762 if (ShowSizes)
Lang Hames4e920e52019-10-04 03:55:26 +0000763 outs() << "Total size of all blocks before pruning: " << S.SizeBeforePruning
764 << "\nTotal size of all blocks after fixups: " << S.SizeAfterFixups
Lang Hames11c8dfa52019-04-20 17:10:34 +0000765 << "\n";
766}
767
768static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000769 return S.ES.lookup(S.JDSearchOrder, EntryPointName);
770}
771
Lang Hames200415c2019-09-04 18:38:29 +0000772struct JITLinkTimers {
Lang Hames41adc372019-09-04 20:26:26 +0000773 TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"};
774 Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG};
775 Timer LinkTimer{"link", "time to link object files", JITLinkTG};
776 Timer RunTimer{"run", "time to execute jitlink'd code", JITLinkTG};
Lang Hames200415c2019-09-04 18:38:29 +0000777};
778
Lang Hames11c8dfa52019-04-20 17:10:34 +0000779int main(int argc, char *argv[]) {
780 InitLLVM X(argc, argv);
781
782 InitializeAllTargetInfos();
783 InitializeAllTargetMCs();
784 InitializeAllDisassemblers();
785
786 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
787 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
788
Lang Hames200415c2019-09-04 18:38:29 +0000789 /// If timers are enabled, create a JITLinkTimers instance.
790 std::unique_ptr<JITLinkTimers> Timers =
791 ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
792
Lang Hames11c8dfa52019-04-20 17:10:34 +0000793 Session S(getFirstFileTriple());
794
Lang Hamesd959a602019-04-24 17:23:05 +0000795 ExitOnErr(sanitizeArguments(S));
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000796
Lang Hames11c8dfa52019-04-20 17:10:34 +0000797 if (!NoProcessSymbols)
798 ExitOnErr(loadProcessSymbols(S));
799 ExitOnErr(loadDylibs());
800
Lang Hames11c8dfa52019-04-20 17:10:34 +0000801
Lang Hames6fd39602019-08-27 15:51:19 +0000802 {
Lang Hames200415c2019-09-04 18:38:29 +0000803 TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000804 ExitOnErr(loadObjects(S));
Lang Hames6fd39602019-08-27 15:51:19 +0000805 }
806
807 JITEvaluatedSymbol EntryPoint = 0;
808 {
Lang Hames200415c2019-09-04 18:38:29 +0000809 TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000810 EntryPoint = ExitOnErr(getMainEntryPoint(S));
Lang Hames6fd39602019-08-27 15:51:19 +0000811 }
Lang Hames11c8dfa52019-04-20 17:10:34 +0000812
813 if (ShowAddrs)
814 S.dumpSessionInfo(outs());
815
816 ExitOnErr(runChecks(S));
817
818 dumpSessionStats(S);
819
820 if (NoExec)
821 return 0;
822
Lang Hames6fd39602019-08-27 15:51:19 +0000823 int Result = 0;
824 {
Lang Hamesece8fed2019-12-02 01:45:49 -0800825 using MainTy = int (*)(int, char *[]);
826 auto EntryFn = jitTargetAddressToFunction<MainTy>(EntryPoint.getAddress());
Lang Hames200415c2019-09-04 18:38:29 +0000827 TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
Lang Hamesece8fed2019-12-02 01:45:49 -0800828 Result = runAsMain(EntryFn, InputArgv, StringRef(InputFiles.front()));
Lang Hames6fd39602019-08-27 15:51:19 +0000829 }
830
Lang Hames6fd39602019-08-27 15:51:19 +0000831 return Result;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000832}