blob: 7edbea23a044f7a9a1ab018b335d17059f5ba20f [file] [log] [blame]
Lang Hames11c8dfa52019-04-20 17:10:34 +00001//===- llvm-jitlink.cpp -- Command line interface/tester for llvm-jitlink -===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This utility provides a simple command line interface to the llvm jitlink
10// library, which makes relocatable object files executable in memory. Its
11// primary function is as a testing utility for the jitlink library.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm-jitlink.h"
16
Lang Hamesf5a885f2019-07-04 00:05:12 +000017#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000018#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
19#include "llvm/MC/MCAsmInfo.h"
20#include "llvm/MC/MCContext.h"
21#include "llvm/MC/MCDisassembler/MCDisassembler.h"
22#include "llvm/MC/MCInstPrinter.h"
23#include "llvm/MC/MCInstrInfo.h"
24#include "llvm/MC/MCRegisterInfo.h"
25#include "llvm/MC/MCSubtargetInfo.h"
26#include "llvm/Object/COFF.h"
27#include "llvm/Object/MachO.h"
28#include "llvm/Object/ObjectFile.h"
29#include "llvm/Support/CommandLine.h"
30#include "llvm/Support/Debug.h"
31#include "llvm/Support/DynamicLibrary.h"
32#include "llvm/Support/InitLLVM.h"
33#include "llvm/Support/MemoryBuffer.h"
Lang Hames335676e2019-09-06 19:21:55 +000034#include "llvm/Support/Process.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000035#include "llvm/Support/TargetRegistry.h"
36#include "llvm/Support/TargetSelect.h"
Lang Hames6fd39602019-08-27 15:51:19 +000037#include "llvm/Support/Timer.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000038
39#include <list>
40#include <string>
41
Lang Hames11c8dfa52019-04-20 17:10:34 +000042#define DEBUG_TYPE "llvm-jitlink"
43
44using namespace llvm;
45using namespace llvm::jitlink;
46using namespace llvm::orc;
47
48static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
49 cl::desc("input files"));
50
51static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
52 cl::init(false));
53
54static cl::list<std::string>
55 CheckFiles("check", cl::desc("File containing verifier checks"),
56 cl::ZeroOrMore);
57
58static cl::opt<std::string>
59 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
60 cl::init(""));
61
62static cl::list<std::string> JITLinkDylibs(
63 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
64 "input file arguments"));
65
66static cl::list<std::string>
67 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
68 cl::ZeroOrMore);
69
Lang Hamesd959a602019-04-24 17:23:05 +000070static cl::list<std::string> InputArgv("args", cl::Positional,
71 cl::desc("<program arguments>..."),
72 cl::ZeroOrMore, cl::PositionalEatsArgs);
73
Lang Hames11c8dfa52019-04-20 17:10:34 +000074static cl::opt<bool>
75 NoProcessSymbols("no-process-syms",
76 cl::desc("Do not resolve to llvm-jitlink process symbols"),
77 cl::init(false));
78
Nico Weber405e62b2019-04-21 23:50:24 +000079static cl::list<std::string> AbsoluteDefs(
80 "define-abs",
81 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
82 cl::ZeroOrMore);
Lang Hames11c8dfa52019-04-20 17:10:34 +000083
84static cl::opt<bool> ShowAddrs(
85 "show-addrs",
86 cl::desc("Print registered symbol, section, got and stub addresses"),
87 cl::init(false));
88
Lang Hames4e920e52019-10-04 03:55:26 +000089static cl::opt<bool> ShowLinkGraph(
Lang Hames11c8dfa52019-04-20 17:10:34 +000090 "show-graph",
Lang Hames4e920e52019-10-04 03:55:26 +000091 cl::desc("Print the link graph after fixups have been applied"),
Lang Hames11c8dfa52019-04-20 17:10:34 +000092 cl::init(false));
93
94static cl::opt<bool> ShowSizes(
Lang Hamesbc76bbc2019-04-21 20:34:19 +000095 "show-sizes",
96 cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
97 cl::init(false));
98
Lang Hames6fd39602019-08-27 15:51:19 +000099static cl::opt<bool> ShowTimes("show-times",
100 cl::desc("Show times for llvm-jitlink phases"),
101 cl::init(false));
102
Lang Hames335676e2019-09-06 19:21:55 +0000103static 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(""));
109
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000110static cl::opt<bool> ShowRelocatedSectionContents(
111 "show-relocated-section-contents",
112 cl::desc("show section contents after fixups have been applied"),
113 cl::init(false));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000114
115ExitOnError ExitOnErr;
116
117namespace llvm {
118
119static raw_ostream &
120operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
Lang Hames23085ec2019-05-12 22:26:33 +0000121 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)";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000126}
127
128static raw_ostream &
129operator<<(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;
134}
135
136static raw_ostream &
137operator<<(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;
145}
146
147static raw_ostream &
148operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) {
149 for (auto &FIKV : FIM)
150 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second;
151 return OS;
152}
153
Lang Hames4e920e52019-10-04 03:55:26 +0000154static uint64_t computeTotalBlockSizes(LinkGraph &G) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000155 uint64_t TotalSize = 0;
Lang Hames4e920e52019-10-04 03:55:26 +0000156 for (auto *B : G.blocks())
157 TotalSize += B->getSize();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000158 return TotalSize;
159}
160
Lang Hames4e920e52019-10-04 03:55:26 +0000161static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000162 constexpr JITTargetAddress DumpWidth = 16;
163 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two");
164
165 // Put sections in address order.
166 std::vector<Section *> Sections;
167 for (auto &S : G.sections())
168 Sections.push_back(&S);
169
170 std::sort(Sections.begin(), Sections.end(),
171 [](const Section *LHS, const Section *RHS) {
Lang Hames4e920e52019-10-04 03:55:26 +0000172 if (LHS->symbols_empty() && RHS->symbols_empty())
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000173 return false;
Lang Hames4e920e52019-10-04 03:55:26 +0000174 if (LHS->symbols_empty())
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000175 return false;
Lang Hames4e920e52019-10-04 03:55:26 +0000176 if (RHS->symbols_empty())
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000177 return true;
Lang Hames4e920e52019-10-04 03:55:26 +0000178 SectionRange LHSRange(*LHS);
179 SectionRange RHSRange(*RHS);
180 return LHSRange.getStart() < RHSRange.getStart();
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000181 });
182
183 for (auto *S : Sections) {
184 OS << S->getName() << " content:";
Lang Hames4e920e52019-10-04 03:55:26 +0000185 if (S->symbols_empty()) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000186 OS << "\n section empty\n";
187 continue;
188 }
189
Lang Hames4e920e52019-10-04 03:55:26 +0000190 // 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();
194 });
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000195
Lang Hames4e920e52019-10-04 03:55:26 +0000196 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();
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000204
Lang Hames4e920e52019-10-04 03:55:26 +0000205 // Pad any space before the symbol starts.
206 while (NextAddr != SymStart) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000207 if (NextAddr % DumpWidth == 0)
208 OS << formatv("\n{0:x16}:", NextAddr);
209 OS << " ";
210 ++NextAddr;
211 }
212
Lang Hames4e920e52019-10-04 03:55:26 +0000213 // Render the symbol content.
214 while (NextAddr != SymEnd) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000215 if (NextAddr % DumpWidth == 0)
216 OS << formatv("\n{0:x16}:", NextAddr);
217 if (IsZeroFill)
218 OS << " 00";
219 else
Lang Hames4e920e52019-10-04 03:55:26 +0000220 OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]);
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000221 ++NextAddr;
222 }
223 }
224 OS << "\n";
225 }
226}
227
Lang Hames335676e2019-09-06 19:21:55 +0000228class JITLinkSlabAllocator final : public JITLinkMemoryManager {
229public:
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));
235 if (Err)
236 return std::move(Err);
237 return std::move(Allocator);
238 }
239
240 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
241 allocate(const SegmentsRequestMap &Request) override {
242
243 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
244
245 // Local class for allocation.
246 class IPMMAlloc : public Allocation {
247 public:
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()};
253 }
254 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
255 assert(SegBlocks.count(Seg) && "No allocation for segment");
256 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
257 }
258 void finalizeAsync(FinalizeContinuation OnFinalize) override {
259 OnFinalize(applyProtections());
260 }
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();
266 }
267
268 private:
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());
278 }
279 return Error::success();
280 }
281
282 AllocationMap SegBlocks;
283 };
284
285 AllocationMap Blocks;
286
287 for (auto &KV : Request) {
288 auto &Seg = KV.second;
289
Lang Hames4e920e52019-10-04 03:55:26 +0000290 if (Seg.getAlignment() > PageSize)
Lang Hames335676e2019-09-06 19:21:55 +0000291 return make_error<StringError>("Cannot request higher than page "
292 "alignment",
293 inconvertibleErrorCode());
294
Lang Hames4e920e52019-10-04 03:55:26 +0000295 if (PageSize % Seg.getAlignment() != 0)
Lang Hames335676e2019-09-06 19:21:55 +0000296 return make_error<StringError>("Page size is not a multiple of "
297 "alignment",
298 inconvertibleErrorCode());
299
Lang Hames4e920e52019-10-04 03:55:26 +0000300 uint64_t ZeroFillStart = Seg.getContentSize();
Lang Hames335676e2019-09-06 19:21:55 +0000301 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
302
303 // Round segment size up to page boundary.
304 SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1);
305
306 // Take segment bytes from the front of the slab.
307 void *SlabBase = SlabRemaining.base();
308 uint64_t SlabRemainingSize = SlabRemaining.allocatedSize();
309
310 if (SegmentSize > SlabRemainingSize)
311 return make_error<StringError>("Slab allocator out of memory",
312 inconvertibleErrorCode());
313
314 sys::MemoryBlock SegMem(SlabBase, SegmentSize);
315 SlabRemaining =
316 sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize,
317 SlabRemainingSize - SegmentSize);
318
319 // Zero out the zero-fill memory.
320 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
321 Seg.getZeroFillSize());
322
323 // Record the block for this segment.
324 Blocks[KV.first] = std::move(SegMem);
325 }
326 return std::unique_ptr<InProcessMemoryManager::Allocation>(
327 new IPMMAlloc(std::move(Blocks)));
328 }
329
330private:
331 JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
332 ErrorAsOutParameter _(&Err);
333
334 PageSize = sys::Process::getPageSizeEstimate();
335
336 if (!isPowerOf2_64(PageSize)) {
337 Err = make_error<StringError>("Page size is not a power of 2",
338 inconvertibleErrorCode());
339 return;
340 }
341
342 // Round slab request up to page size.
343 SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
344
345 const sys::Memory::ProtectionFlags ReadWrite =
346 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
347 sys::Memory::MF_WRITE);
348
349 std::error_code EC;
350 SlabRemaining =
351 sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
352
353 if (EC) {
354 Err = errorCodeToError(EC);
355 return;
356 }
357 }
358
359 sys::MemoryBlock SlabRemaining;
360 uint64_t PageSize = 0;
361};
362
363Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
364 SizeString = SizeString.trim();
365
366 uint64_t Units = 1024;
367
368 if (SizeString.endswith_lower("kb"))
369 SizeString = SizeString.drop_back(2).rtrim();
370 else if (SizeString.endswith_lower("mb")) {
371 Units = 1024 * 1024;
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();
376 }
377
378 uint64_t SlabSize = 0;
379 if (SizeString.getAsInteger(10, SlabSize))
380 return make_error<StringError>("Invalid numeric format for slab size",
381 inconvertibleErrorCode());
382
383 return SlabSize * Units;
384}
385
386static std::unique_ptr<jitlink::JITLinkMemoryManager> createMemoryManager() {
387 if (!SlabAllocateSizeString.empty()) {
388 auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
389 return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
390 }
391 return std::make_unique<jitlink::InProcessMemoryManager>();
392}
393
394Session::Session(Triple TT)
395 : MemMgr(createMemoryManager()), ObjLayer(ES, *MemMgr), TT(std::move(TT)) {
Lang Hamesa9fdf372019-04-26 22:58:39 +0000396
397 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
398 /// Session.
399 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
400 public:
401 JITLinkSessionPlugin(Session &S) : S(S) {}
402 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
403 PassConfiguration &PassConfig) {
404 S.modifyPassConfig(TT, PassConfig);
405 }
406
407 private:
408 Session &S;
409 };
410
411 if (!NoExec && !TT.isOSWindows())
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000412 ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
Lang Hamesf5a885f2019-07-04 00:05:12 +0000413 InProcessEHFrameRegistrar::getInstance()));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000414
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000415 ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000416}
Lang Hames11c8dfa52019-04-20 17:10:34 +0000417
418void Session::dumpSessionInfo(raw_ostream &OS) {
419 OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
420}
421
422void Session::modifyPassConfig(const Triple &FTT,
423 PassConfiguration &PassConfig) {
424 if (!CheckFiles.empty())
Lang Hames4e920e52019-10-04 03:55:26 +0000425 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000426 if (TT.getObjectFormat() == Triple::MachO)
427 return registerMachOStubsAndGOT(*this, G);
428 return make_error<StringError>("Unsupported object format for GOT/stub "
429 "registration",
430 inconvertibleErrorCode());
431 });
432
Lang Hames4e920e52019-10-04 03:55:26 +0000433 if (ShowLinkGraph)
434 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
435 outs() << "Link graph post-fixup:\n";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000436 G.dump(outs());
437 return Error::success();
438 });
439
Lang Hames11c8dfa52019-04-20 17:10:34 +0000440 if (ShowSizes) {
Lang Hames4e920e52019-10-04 03:55:26 +0000441 PassConfig.PrePrunePasses.push_back([this](LinkGraph &G) -> Error {
442 SizeBeforePruning += computeTotalBlockSizes(G);
443 return Error::success();
444 });
445 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) -> Error {
446 SizeAfterFixups += computeTotalBlockSizes(G);
447 return Error::success();
448 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000449 }
450
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000451 if (ShowRelocatedSectionContents)
Lang Hames4e920e52019-10-04 03:55:26 +0000452 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000453 outs() << "Relocated section contents for " << G.getName() << ":\n";
454 dumpSectionContents(outs(), G);
455 return Error::success();
456 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000457}
458
459Expected<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;
465}
466
467Expected<Session::MemoryRegionInfo &>
468Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
469 auto FI = findFileInfo(FileName);
470 if (!FI)
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 +
476 "\"",
477 inconvertibleErrorCode());
478 return SecInfoItr->second;
479}
480
481Expected<Session::MemoryRegionInfo &>
482Session::findStubInfo(StringRef FileName, StringRef TargetName) {
483 auto FI = findFileInfo(FileName);
484 if (!FI)
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 +
490 "\"",
491 inconvertibleErrorCode());
492 return StubInfoItr->second;
493}
494
495Expected<Session::MemoryRegionInfo &>
496Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) {
497 auto FI = findFileInfo(FileName);
498 if (!FI)
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 +
504 "\"",
505 inconvertibleErrorCode());
506 return GOTInfoItr->second;
507}
508
509bool Session::isSymbolRegistered(StringRef SymbolName) {
510 return SymbolInfos.count(SymbolName);
511}
512
513Expected<Session::MemoryRegionInfo &>
514Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
515 auto SymInfoItr = SymbolInfos.find(SymbolName);
516 if (SymInfoItr == SymbolInfos.end())
517 return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName +
518 " not found",
519 inconvertibleErrorCode());
520 return SymInfoItr->second;
521}
522
523} // end namespace llvm
524
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000525Triple getFirstFileTriple() {
526 assert(!InputFiles.empty() && "InputFiles can not be empty");
527 auto ObjBuffer =
528 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
529 auto Obj = ExitOnErr(
530 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
531 return Obj->makeTriple();
532}
533
Lang Hamesd959a602019-04-24 17:23:05 +0000534Error sanitizeArguments(const Session &S) {
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000535 if (EntryPointName.empty()) {
536 if (S.TT.getObjectFormat() == Triple::MachO)
537 EntryPointName = "_main";
538 else
539 EntryPointName = "main";
540 }
Lang Hamesd959a602019-04-24 17:23:05 +0000541
542 if (NoExec && !InputArgv.empty())
543 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
544
545 return Error::success();
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000546}
547
Lang Hames11c8dfa52019-04-20 17:10:34 +0000548Error loadProcessSymbols(Session &S) {
549 std::string ErrMsg;
550 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg))
551 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
552
553 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0';
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000554 auto InternedEntryPointName = S.ES.intern(EntryPointName);
555 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
556 return Name != InternedEntryPointName;
557 };
Lang Hames52a34a72019-08-13 16:05:18 +0000558 S.ES.getMainJITDylib().addGenerator(
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000559 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
560 GlobalPrefix, FilterMainEntryPoint)));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000561
562 return Error::success();
563}
564
565Error loadDylibs() {
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());
571 std::string ErrMsg;
572 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
573 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
574 }
575
576 return Error::success();
577}
578
Lang Hames11c8dfa52019-04-20 17:10:34 +0000579Error loadObjects(Session &S) {
580
581 std::map<unsigned, JITDylib *> IdxToJLD;
582
583 // First, set up JITDylibs.
584 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
585 {
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");
591
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);
597 unsigned JDIdx =
598 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin());
599 IdxToJLD[JDIdx] = &JD;
600 S.JDSearchOrder.push_back(&JD);
601 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n");
602 }
603
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) {
608 if (JD2 == JD)
609 continue;
610 O.push_back(std::make_pair(JD2, false));
611 }
612 JD->setSearchOrder(std::move(O));
613 }
614 }
615
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";);
626 auto ObjBuffer =
627 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile)));
628 ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer)));
629 }
630
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;
638
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();
647
648 uint64_t Addr;
649 if (AddrStr.getAsInteger(0, Addr))
650 return make_error<StringError>("Invalid address expression \"" + AddrStr +
651 "\" in absolute define \"" + AbsDefStmt +
652 "\"",
653 inconvertibleErrorCode());
654 JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported);
655 if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}})))
656 return Err;
657
658 // Register the absolute symbol with the session symbol infos.
659 S.SymbolInfos[Name] = { StringRef(), Addr };
660 }
661
662 LLVM_DEBUG({
663 dbgs() << "Dylib search order is [ ";
664 for (auto *JD : S.JDSearchOrder)
665 dbgs() << JD->getName() << " ";
666 dbgs() << "]\n";
667 });
668
669 return Error::success();
670}
671
672Error runChecks(Session &S) {
673
674 auto TripleName = S.TT.str();
675 std::string ErrorStr;
676 const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr);
677 if (!TheTarget)
678 ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName +
679 "': " + ErrorStr,
680 inconvertibleErrorCode()));
681
682 std::unique_ptr<MCSubtargetInfo> STI(
683 TheTarget->createMCSubtargetInfo(TripleName, "", ""));
684 if (!STI)
685 ExitOnErr(
686 make_error<StringError>("Unable to create subtarget for " + TripleName,
687 inconvertibleErrorCode()));
688
689 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
690 if (!MRI)
691 ExitOnErr(make_error<StringError>("Unable to create target register info "
692 "for " +
693 TripleName,
694 inconvertibleErrorCode()));
695
696 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
697 if (!MAI)
698 ExitOnErr(make_error<StringError>("Unable to create target asm info " +
699 TripleName,
700 inconvertibleErrorCode()));
701
702 MCContext Ctx(MAI.get(), MRI.get(), nullptr);
703
704 std::unique_ptr<MCDisassembler> Disassembler(
705 TheTarget->createMCDisassembler(*STI, Ctx));
706 if (!Disassembler)
707 ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
708 TripleName,
709 inconvertibleErrorCode()));
710
711 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
712
713 std::unique_ptr<MCInstPrinter> InstPrinter(
714 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
715
716 auto IsSymbolValid = [&S](StringRef Symbol) {
717 return S.isSymbolRegistered(Symbol);
718 };
719
720 auto GetSymbolInfo = [&S](StringRef Symbol) {
721 return S.findSymbolInfo(Symbol, "Can not get symbol info");
722 };
723
724 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
725 return S.findSectionInfo(FileName, SectionName);
726 };
727
728 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
729 return S.findStubInfo(FileName, SectionName);
730 };
731
732 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
733 return S.findGOTEntryInfo(FileName, SectionName);
734 };
735
736 RuntimeDyldChecker Checker(
737 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
738 S.TT.isLittleEndian() ? support::little : support::big,
739 Disassembler.get(), InstPrinter.get(), dbgs());
740
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()));
747 }
748
749 return Error::success();
750}
751
752static void dumpSessionStats(Session &S) {
753 if (ShowSizes)
Lang Hames4e920e52019-10-04 03:55:26 +0000754 outs() << "Total size of all blocks before pruning: " << S.SizeBeforePruning
755 << "\nTotal size of all blocks after fixups: " << S.SizeAfterFixups
Lang Hames11c8dfa52019-04-20 17:10:34 +0000756 << "\n";
757}
758
759static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000760 return S.ES.lookup(S.JDSearchOrder, EntryPointName);
761}
762
763Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
764 assert(EntryPoint.getAddress() && "Entry point address should not be null");
765
766 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000767 auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000768 strcpy(PNStorage.get(), JITProgramName);
769
770 std::vector<const char *> EntryPointArgs;
771 EntryPointArgs.push_back(PNStorage.get());
Lang Hamesd959a602019-04-24 17:23:05 +0000772 for (auto &InputArg : InputArgv)
773 EntryPointArgs.push_back(InputArg.data());
Lang Hames11c8dfa52019-04-20 17:10:34 +0000774 EntryPointArgs.push_back(nullptr);
775
776 using MainTy = int (*)(int, const char *[]);
777 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
778
779 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
780}
781
Lang Hames200415c2019-09-04 18:38:29 +0000782struct JITLinkTimers {
Lang Hames41adc372019-09-04 20:26:26 +0000783 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};
Lang Hames200415c2019-09-04 18:38:29 +0000787};
788
Lang Hames11c8dfa52019-04-20 17:10:34 +0000789int main(int argc, char *argv[]) {
790 InitLLVM X(argc, argv);
791
792 InitializeAllTargetInfos();
793 InitializeAllTargetMCs();
794 InitializeAllDisassemblers();
795
796 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
797 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
798
Lang Hames200415c2019-09-04 18:38:29 +0000799 /// If timers are enabled, create a JITLinkTimers instance.
800 std::unique_ptr<JITLinkTimers> Timers =
801 ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
802
Lang Hames11c8dfa52019-04-20 17:10:34 +0000803 Session S(getFirstFileTriple());
804
Lang Hamesd959a602019-04-24 17:23:05 +0000805 ExitOnErr(sanitizeArguments(S));
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000806
Lang Hames11c8dfa52019-04-20 17:10:34 +0000807 if (!NoProcessSymbols)
808 ExitOnErr(loadProcessSymbols(S));
809 ExitOnErr(loadDylibs());
810
Lang Hames11c8dfa52019-04-20 17:10:34 +0000811
Lang Hames6fd39602019-08-27 15:51:19 +0000812 {
Lang Hames200415c2019-09-04 18:38:29 +0000813 TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000814 ExitOnErr(loadObjects(S));
Lang Hames6fd39602019-08-27 15:51:19 +0000815 }
816
817 JITEvaluatedSymbol EntryPoint = 0;
818 {
Lang Hames200415c2019-09-04 18:38:29 +0000819 TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000820 EntryPoint = ExitOnErr(getMainEntryPoint(S));
Lang Hames6fd39602019-08-27 15:51:19 +0000821 }
Lang Hames11c8dfa52019-04-20 17:10:34 +0000822
823 if (ShowAddrs)
824 S.dumpSessionInfo(outs());
825
826 ExitOnErr(runChecks(S));
827
828 dumpSessionStats(S);
829
830 if (NoExec)
831 return 0;
832
Lang Hames6fd39602019-08-27 15:51:19 +0000833 int Result = 0;
834 {
Lang Hames200415c2019-09-04 18:38:29 +0000835 TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000836 Result = ExitOnErr(runEntryPoint(S, EntryPoint));
Lang Hames6fd39602019-08-27 15:51:19 +0000837 }
838
Lang Hames6fd39602019-08-27 15:51:19 +0000839 return Result;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000840}