blob: 251e79cf56d12b2f0dd3b55b5f9a74df75eeb112 [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>
60 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
61 cl::init(""));
62
63static cl::list<std::string> JITLinkDylibs(
64 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
65 "input file arguments"));
66
67static cl::list<std::string>
68 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
69 cl::ZeroOrMore);
70
Lang Hamesd959a602019-04-24 17:23:05 +000071static cl::list<std::string> InputArgv("args", cl::Positional,
72 cl::desc("<program arguments>..."),
73 cl::ZeroOrMore, cl::PositionalEatsArgs);
74
Lang Hames11c8dfa52019-04-20 17:10:34 +000075static cl::opt<bool>
76 NoProcessSymbols("no-process-syms",
77 cl::desc("Do not resolve to llvm-jitlink process symbols"),
78 cl::init(false));
79
Nico Weber405e62b2019-04-21 23:50:24 +000080static cl::list<std::string> AbsoluteDefs(
81 "define-abs",
82 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
83 cl::ZeroOrMore);
Lang Hames11c8dfa52019-04-20 17:10:34 +000084
85static cl::opt<bool> ShowAddrs(
86 "show-addrs",
87 cl::desc("Print registered symbol, section, got and stub addresses"),
88 cl::init(false));
89
Lang Hames4e920e52019-10-04 03:55:26 +000090static cl::opt<bool> ShowLinkGraph(
Lang Hames11c8dfa52019-04-20 17:10:34 +000091 "show-graph",
Lang Hames4e920e52019-10-04 03:55:26 +000092 cl::desc("Print the link graph after fixups have been applied"),
Lang Hames11c8dfa52019-04-20 17:10:34 +000093 cl::init(false));
94
95static cl::opt<bool> ShowSizes(
Lang Hamesbc76bbc2019-04-21 20:34:19 +000096 "show-sizes",
97 cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
98 cl::init(false));
99
Lang Hames6fd39602019-08-27 15:51:19 +0000100static cl::opt<bool> ShowTimes("show-times",
101 cl::desc("Show times for llvm-jitlink phases"),
102 cl::init(false));
103
Lang Hames335676e2019-09-06 19:21:55 +0000104static cl::opt<std::string> SlabAllocateSizeString(
105 "slab-allocate",
106 cl::desc("Allocate from a slab of the given size "
107 "(allowable suffixes: Kb, Mb, Gb. default = "
108 "Kb)"),
109 cl::init(""));
110
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000111static cl::opt<bool> ShowRelocatedSectionContents(
112 "show-relocated-section-contents",
113 cl::desc("show section contents after fixups have been applied"),
114 cl::init(false));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000115
116ExitOnError ExitOnErr;
117
118namespace llvm {
119
120static raw_ostream &
121operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
Lang Hames23085ec2019-05-12 22:26:33 +0000122 return OS << "target addr = "
123 << format("0x%016" PRIx64, MRI.getTargetAddress())
124 << ", content: " << (const void *)MRI.getContent().data() << " -- "
125 << (const void *)(MRI.getContent().data() + MRI.getContent().size())
126 << " (" << MRI.getContent().size() << " bytes)";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000127}
128
129static raw_ostream &
130operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) {
131 OS << "Symbols:\n";
132 for (auto &SKV : SIM)
133 OS << " \"" << SKV.first() << "\" " << SKV.second << "\n";
134 return OS;
135}
136
137static raw_ostream &
138operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
139 for (auto &SIKV : FI.SectionInfos)
140 OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
141 for (auto &GOTKV : FI.GOTEntryInfos)
142 OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
143 for (auto &StubKV : FI.StubInfos)
144 OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
145 return OS;
146}
147
148static raw_ostream &
149operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) {
150 for (auto &FIKV : FIM)
151 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second;
152 return OS;
153}
154
Lang Hames4e920e52019-10-04 03:55:26 +0000155static uint64_t computeTotalBlockSizes(LinkGraph &G) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000156 uint64_t TotalSize = 0;
Lang Hames4e920e52019-10-04 03:55:26 +0000157 for (auto *B : G.blocks())
158 TotalSize += B->getSize();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000159 return TotalSize;
160}
161
Lang Hames4e920e52019-10-04 03:55:26 +0000162static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000163 constexpr JITTargetAddress DumpWidth = 16;
164 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two");
165
166 // Put sections in address order.
167 std::vector<Section *> Sections;
168 for (auto &S : G.sections())
169 Sections.push_back(&S);
170
171 std::sort(Sections.begin(), Sections.end(),
172 [](const Section *LHS, const Section *RHS) {
Lang Hames4e920e52019-10-04 03:55:26 +0000173 if (LHS->symbols_empty() && RHS->symbols_empty())
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000174 return false;
Lang Hames4e920e52019-10-04 03:55:26 +0000175 if (LHS->symbols_empty())
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000176 return false;
Lang Hames4e920e52019-10-04 03:55:26 +0000177 if (RHS->symbols_empty())
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000178 return true;
Lang Hames4e920e52019-10-04 03:55:26 +0000179 SectionRange LHSRange(*LHS);
180 SectionRange RHSRange(*RHS);
181 return LHSRange.getStart() < RHSRange.getStart();
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000182 });
183
184 for (auto *S : Sections) {
185 OS << S->getName() << " content:";
Lang Hames4e920e52019-10-04 03:55:26 +0000186 if (S->symbols_empty()) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000187 OS << "\n section empty\n";
188 continue;
189 }
190
Lang Hames4e920e52019-10-04 03:55:26 +0000191 // Sort symbols into order, then render.
192 std::vector<Symbol *> Syms(S->symbols().begin(), S->symbols().end());
193 llvm::sort(Syms, [](const Symbol *LHS, const Symbol *RHS) {
194 return LHS->getAddress() < RHS->getAddress();
195 });
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000196
Lang Hames4e920e52019-10-04 03:55:26 +0000197 JITTargetAddress NextAddr = Syms.front()->getAddress() & ~(DumpWidth - 1);
198 for (auto *Sym : Syms) {
199 bool IsZeroFill = Sym->getBlock().isZeroFill();
200 JITTargetAddress SymStart = Sym->getAddress();
201 JITTargetAddress SymSize = Sym->getSize();
202 JITTargetAddress SymEnd = SymStart + SymSize;
203 const uint8_t *SymData =
204 IsZeroFill ? nullptr : Sym->getSymbolContent().bytes_begin();
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000205
Lang Hames4e920e52019-10-04 03:55:26 +0000206 // Pad any space before the symbol starts.
207 while (NextAddr != SymStart) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000208 if (NextAddr % DumpWidth == 0)
209 OS << formatv("\n{0:x16}:", NextAddr);
210 OS << " ";
211 ++NextAddr;
212 }
213
Lang Hames4e920e52019-10-04 03:55:26 +0000214 // Render the symbol content.
215 while (NextAddr != SymEnd) {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000216 if (NextAddr % DumpWidth == 0)
217 OS << formatv("\n{0:x16}:", NextAddr);
218 if (IsZeroFill)
219 OS << " 00";
220 else
Lang Hames4e920e52019-10-04 03:55:26 +0000221 OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]);
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000222 ++NextAddr;
223 }
224 }
225 OS << "\n";
226 }
227}
228
Lang Hames335676e2019-09-06 19:21:55 +0000229class JITLinkSlabAllocator final : public JITLinkMemoryManager {
230public:
231 static Expected<std::unique_ptr<JITLinkSlabAllocator>>
232 Create(uint64_t SlabSize) {
233 Error Err = Error::success();
234 std::unique_ptr<JITLinkSlabAllocator> Allocator(
235 new JITLinkSlabAllocator(SlabSize, Err));
236 if (Err)
237 return std::move(Err);
238 return std::move(Allocator);
239 }
240
241 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
242 allocate(const SegmentsRequestMap &Request) override {
243
244 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
245
246 // Local class for allocation.
247 class IPMMAlloc : public Allocation {
248 public:
249 IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
250 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
251 assert(SegBlocks.count(Seg) && "No allocation for segment");
252 return {static_cast<char *>(SegBlocks[Seg].base()),
253 SegBlocks[Seg].allocatedSize()};
254 }
255 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
256 assert(SegBlocks.count(Seg) && "No allocation for segment");
257 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
258 }
259 void finalizeAsync(FinalizeContinuation OnFinalize) override {
260 OnFinalize(applyProtections());
261 }
262 Error deallocate() override {
263 for (auto &KV : SegBlocks)
264 if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
265 return errorCodeToError(EC);
266 return Error::success();
267 }
268
269 private:
270 Error applyProtections() {
271 for (auto &KV : SegBlocks) {
272 auto &Prot = KV.first;
273 auto &Block = KV.second;
274 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
275 return errorCodeToError(EC);
276 if (Prot & sys::Memory::MF_EXEC)
277 sys::Memory::InvalidateInstructionCache(Block.base(),
278 Block.allocatedSize());
279 }
280 return Error::success();
281 }
282
283 AllocationMap SegBlocks;
284 };
285
286 AllocationMap Blocks;
287
288 for (auto &KV : Request) {
289 auto &Seg = KV.second;
290
Lang Hames4e920e52019-10-04 03:55:26 +0000291 if (Seg.getAlignment() > PageSize)
Lang Hames335676e2019-09-06 19:21:55 +0000292 return make_error<StringError>("Cannot request higher than page "
293 "alignment",
294 inconvertibleErrorCode());
295
Lang Hames4e920e52019-10-04 03:55:26 +0000296 if (PageSize % Seg.getAlignment() != 0)
Lang Hames335676e2019-09-06 19:21:55 +0000297 return make_error<StringError>("Page size is not a multiple of "
298 "alignment",
299 inconvertibleErrorCode());
300
Lang Hames4e920e52019-10-04 03:55:26 +0000301 uint64_t ZeroFillStart = Seg.getContentSize();
Lang Hames335676e2019-09-06 19:21:55 +0000302 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
303
304 // Round segment size up to page boundary.
305 SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1);
306
307 // Take segment bytes from the front of the slab.
308 void *SlabBase = SlabRemaining.base();
309 uint64_t SlabRemainingSize = SlabRemaining.allocatedSize();
310
311 if (SegmentSize > SlabRemainingSize)
312 return make_error<StringError>("Slab allocator out of memory",
313 inconvertibleErrorCode());
314
315 sys::MemoryBlock SegMem(SlabBase, SegmentSize);
316 SlabRemaining =
317 sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize,
318 SlabRemainingSize - SegmentSize);
319
320 // Zero out the zero-fill memory.
321 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
322 Seg.getZeroFillSize());
323
324 // Record the block for this segment.
325 Blocks[KV.first] = std::move(SegMem);
326 }
327 return std::unique_ptr<InProcessMemoryManager::Allocation>(
328 new IPMMAlloc(std::move(Blocks)));
329 }
330
331private:
332 JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
333 ErrorAsOutParameter _(&Err);
334
335 PageSize = sys::Process::getPageSizeEstimate();
336
337 if (!isPowerOf2_64(PageSize)) {
338 Err = make_error<StringError>("Page size is not a power of 2",
339 inconvertibleErrorCode());
340 return;
341 }
342
343 // Round slab request up to page size.
344 SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
345
346 const sys::Memory::ProtectionFlags ReadWrite =
347 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
348 sys::Memory::MF_WRITE);
349
350 std::error_code EC;
351 SlabRemaining =
352 sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
353
354 if (EC) {
355 Err = errorCodeToError(EC);
356 return;
357 }
358 }
359
360 sys::MemoryBlock SlabRemaining;
361 uint64_t PageSize = 0;
362};
363
364Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
365 SizeString = SizeString.trim();
366
367 uint64_t Units = 1024;
368
369 if (SizeString.endswith_lower("kb"))
370 SizeString = SizeString.drop_back(2).rtrim();
371 else if (SizeString.endswith_lower("mb")) {
372 Units = 1024 * 1024;
373 SizeString = SizeString.drop_back(2).rtrim();
374 } else if (SizeString.endswith_lower("gb")) {
375 Units = 1024 * 1024 * 1024;
376 SizeString = SizeString.drop_back(2).rtrim();
377 }
378
379 uint64_t SlabSize = 0;
380 if (SizeString.getAsInteger(10, SlabSize))
381 return make_error<StringError>("Invalid numeric format for slab size",
382 inconvertibleErrorCode());
383
384 return SlabSize * Units;
385}
386
387static std::unique_ptr<jitlink::JITLinkMemoryManager> createMemoryManager() {
388 if (!SlabAllocateSizeString.empty()) {
389 auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
390 return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
391 }
392 return std::make_unique<jitlink::InProcessMemoryManager>();
393}
394
395Session::Session(Triple TT)
396 : MemMgr(createMemoryManager()), ObjLayer(ES, *MemMgr), TT(std::move(TT)) {
Lang Hamesa9fdf372019-04-26 22:58:39 +0000397
398 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
399 /// Session.
400 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
401 public:
402 JITLinkSessionPlugin(Session &S) : S(S) {}
403 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
404 PassConfiguration &PassConfig) {
405 S.modifyPassConfig(TT, PassConfig);
406 }
407
408 private:
409 Session &S;
410 };
411
412 if (!NoExec && !TT.isOSWindows())
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000413 ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
Lang Hamesf5a885f2019-07-04 00:05:12 +0000414 InProcessEHFrameRegistrar::getInstance()));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000415
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000416 ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
Lang Hamesa9fdf372019-04-26 22:58:39 +0000417}
Lang Hames11c8dfa52019-04-20 17:10:34 +0000418
419void Session::dumpSessionInfo(raw_ostream &OS) {
420 OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
421}
422
423void Session::modifyPassConfig(const Triple &FTT,
424 PassConfiguration &PassConfig) {
425 if (!CheckFiles.empty())
Lang Hames4e920e52019-10-04 03:55:26 +0000426 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000427 if (TT.getObjectFormat() == Triple::MachO)
428 return registerMachOStubsAndGOT(*this, G);
429 return make_error<StringError>("Unsupported object format for GOT/stub "
430 "registration",
431 inconvertibleErrorCode());
432 });
433
Lang Hames4e920e52019-10-04 03:55:26 +0000434 if (ShowLinkGraph)
435 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
436 outs() << "Link graph post-fixup:\n";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000437 G.dump(outs());
438 return Error::success();
439 });
440
Lang Hames11c8dfa52019-04-20 17:10:34 +0000441 if (ShowSizes) {
Lang Hames4e920e52019-10-04 03:55:26 +0000442 PassConfig.PrePrunePasses.push_back([this](LinkGraph &G) -> Error {
443 SizeBeforePruning += computeTotalBlockSizes(G);
444 return Error::success();
445 });
446 PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) -> Error {
447 SizeAfterFixups += computeTotalBlockSizes(G);
448 return Error::success();
449 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000450 }
451
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000452 if (ShowRelocatedSectionContents)
Lang Hames4e920e52019-10-04 03:55:26 +0000453 PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error {
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000454 outs() << "Relocated section contents for " << G.getName() << ":\n";
455 dumpSectionContents(outs(), G);
456 return Error::success();
457 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000458}
459
460Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) {
461 auto FileInfoItr = FileInfos.find(FileName);
462 if (FileInfoItr == FileInfos.end())
463 return make_error<StringError>("file \"" + FileName + "\" not recognized",
464 inconvertibleErrorCode());
465 return FileInfoItr->second;
466}
467
468Expected<Session::MemoryRegionInfo &>
469Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
470 auto FI = findFileInfo(FileName);
471 if (!FI)
472 return FI.takeError();
473 auto SecInfoItr = FI->SectionInfos.find(SectionName);
474 if (SecInfoItr == FI->SectionInfos.end())
475 return make_error<StringError>("no section \"" + SectionName +
476 "\" registered for file \"" + FileName +
477 "\"",
478 inconvertibleErrorCode());
479 return SecInfoItr->second;
480}
481
482Expected<Session::MemoryRegionInfo &>
483Session::findStubInfo(StringRef FileName, StringRef TargetName) {
484 auto FI = findFileInfo(FileName);
485 if (!FI)
486 return FI.takeError();
487 auto StubInfoItr = FI->StubInfos.find(TargetName);
488 if (StubInfoItr == FI->StubInfos.end())
489 return make_error<StringError>("no stub for \"" + TargetName +
490 "\" registered for file \"" + FileName +
491 "\"",
492 inconvertibleErrorCode());
493 return StubInfoItr->second;
494}
495
496Expected<Session::MemoryRegionInfo &>
497Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) {
498 auto FI = findFileInfo(FileName);
499 if (!FI)
500 return FI.takeError();
501 auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName);
502 if (GOTInfoItr == FI->GOTEntryInfos.end())
503 return make_error<StringError>("no GOT entry for \"" + TargetName +
504 "\" registered for file \"" + FileName +
505 "\"",
506 inconvertibleErrorCode());
507 return GOTInfoItr->second;
508}
509
510bool Session::isSymbolRegistered(StringRef SymbolName) {
511 return SymbolInfos.count(SymbolName);
512}
513
514Expected<Session::MemoryRegionInfo &>
515Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
516 auto SymInfoItr = SymbolInfos.find(SymbolName);
517 if (SymInfoItr == SymbolInfos.end())
518 return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName +
519 " not found",
520 inconvertibleErrorCode());
521 return SymInfoItr->second;
522}
523
524} // end namespace llvm
525
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000526Triple getFirstFileTriple() {
527 assert(!InputFiles.empty() && "InputFiles can not be empty");
528 auto ObjBuffer =
529 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
530 auto Obj = ExitOnErr(
531 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
532 return Obj->makeTriple();
533}
534
Lang Hamesd959a602019-04-24 17:23:05 +0000535Error sanitizeArguments(const Session &S) {
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000536 if (EntryPointName.empty()) {
537 if (S.TT.getObjectFormat() == Triple::MachO)
538 EntryPointName = "_main";
539 else
540 EntryPointName = "main";
541 }
Lang Hamesd959a602019-04-24 17:23:05 +0000542
543 if (NoExec && !InputArgv.empty())
544 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
545
546 return Error::success();
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000547}
548
Lang Hames11c8dfa52019-04-20 17:10:34 +0000549Error loadProcessSymbols(Session &S) {
550 std::string ErrMsg;
551 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg))
552 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
553
554 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0';
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000555 auto InternedEntryPointName = S.ES.intern(EntryPointName);
556 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
557 return Name != InternedEntryPointName;
558 };
Lang Hames52a34a72019-08-13 16:05:18 +0000559 S.ES.getMainJITDylib().addGenerator(
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000560 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
561 GlobalPrefix, FilterMainEntryPoint)));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000562
563 return Error::success();
564}
565
566Error loadDylibs() {
567 // FIXME: This should all be handled inside DynamicLibrary.
568 for (const auto &Dylib : Dylibs) {
569 if (!sys::fs::is_regular_file(Dylib))
570 return make_error<StringError>("\"" + Dylib + "\" is not a regular file",
571 inconvertibleErrorCode());
572 std::string ErrMsg;
573 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
574 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
575 }
576
577 return Error::success();
578}
579
Lang Hames11c8dfa52019-04-20 17:10:34 +0000580Error loadObjects(Session &S) {
581
582 std::map<unsigned, JITDylib *> IdxToJLD;
583
584 // First, set up JITDylibs.
585 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
586 {
587 // Create a "main" JITLinkDylib.
588 auto &MainJD = S.ES.getMainJITDylib();
589 IdxToJLD[0] = &MainJD;
590 S.JDSearchOrder.push_back(&MainJD);
591 LLVM_DEBUG(dbgs() << " 0: " << MainJD.getName() << "\n");
592
593 // Add any extra JITLinkDylibs from the command line.
594 std::string JDNamePrefix("lib");
595 for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end();
596 JLDItr != JLDEnd; ++JLDItr) {
597 auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr);
598 unsigned JDIdx =
599 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin());
600 IdxToJLD[JDIdx] = &JD;
601 S.JDSearchOrder.push_back(&JD);
602 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n");
603 }
604
605 // Set every dylib to link against every other, in command line order.
606 for (auto *JD : S.JDSearchOrder) {
607 JITDylibSearchList O;
608 for (auto *JD2 : S.JDSearchOrder) {
609 if (JD2 == JD)
610 continue;
611 O.push_back(std::make_pair(JD2, false));
612 }
613 JD->setSearchOrder(std::move(O));
614 }
615 }
616
617 // Load each object into the corresponding JITDylib..
618 LLVM_DEBUG(dbgs() << "Adding objects...\n");
619 for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
620 InputFileItr != InputFileEnd; ++InputFileItr) {
621 unsigned InputFileArgIdx =
622 InputFiles.getPosition(InputFileItr - InputFiles.begin());
623 StringRef InputFile = *InputFileItr;
624 auto &JD = *std::prev(IdxToJLD.lower_bound(InputFileArgIdx))->second;
625 LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
626 << "\" to " << JD.getName() << "\n";);
627 auto ObjBuffer =
628 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile)));
629 ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer)));
630 }
631
632 // Define absolute symbols.
633 LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n");
634 for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end();
635 AbsDefItr != AbsDefEnd; ++AbsDefItr) {
636 unsigned AbsDefArgIdx =
637 AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin());
638 auto &JD = *std::prev(IdxToJLD.lower_bound(AbsDefArgIdx))->second;
639
640 StringRef AbsDefStmt = *AbsDefItr;
641 size_t EqIdx = AbsDefStmt.find_first_of('=');
642 if (EqIdx == StringRef::npos)
643 return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt +
644 "\". Syntax: <name>=<addr>",
645 inconvertibleErrorCode());
646 StringRef Name = AbsDefStmt.substr(0, EqIdx).trim();
647 StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim();
648
649 uint64_t Addr;
650 if (AddrStr.getAsInteger(0, Addr))
651 return make_error<StringError>("Invalid address expression \"" + AddrStr +
652 "\" in absolute define \"" + AbsDefStmt +
653 "\"",
654 inconvertibleErrorCode());
655 JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported);
656 if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}})))
657 return Err;
658
659 // Register the absolute symbol with the session symbol infos.
660 S.SymbolInfos[Name] = { StringRef(), Addr };
661 }
662
663 LLVM_DEBUG({
664 dbgs() << "Dylib search order is [ ";
665 for (auto *JD : S.JDSearchOrder)
666 dbgs() << JD->getName() << " ";
667 dbgs() << "]\n";
668 });
669
670 return Error::success();
671}
672
673Error runChecks(Session &S) {
674
675 auto TripleName = S.TT.str();
676 std::string ErrorStr;
677 const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr);
678 if (!TheTarget)
679 ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName +
680 "': " + ErrorStr,
681 inconvertibleErrorCode()));
682
683 std::unique_ptr<MCSubtargetInfo> STI(
684 TheTarget->createMCSubtargetInfo(TripleName, "", ""));
685 if (!STI)
686 ExitOnErr(
687 make_error<StringError>("Unable to create subtarget for " + TripleName,
688 inconvertibleErrorCode()));
689
690 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
691 if (!MRI)
692 ExitOnErr(make_error<StringError>("Unable to create target register info "
693 "for " +
694 TripleName,
695 inconvertibleErrorCode()));
696
Mirko Brkusanin4b63ca12019-10-23 12:24:35 +0200697 MCTargetOptions MCOptions;
698 std::unique_ptr<MCAsmInfo> MAI(
699 TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000700 if (!MAI)
701 ExitOnErr(make_error<StringError>("Unable to create target asm info " +
702 TripleName,
703 inconvertibleErrorCode()));
704
705 MCContext Ctx(MAI.get(), MRI.get(), nullptr);
706
707 std::unique_ptr<MCDisassembler> Disassembler(
708 TheTarget->createMCDisassembler(*STI, Ctx));
709 if (!Disassembler)
710 ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
711 TripleName,
712 inconvertibleErrorCode()));
713
714 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
715
716 std::unique_ptr<MCInstPrinter> InstPrinter(
717 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
718
719 auto IsSymbolValid = [&S](StringRef Symbol) {
720 return S.isSymbolRegistered(Symbol);
721 };
722
723 auto GetSymbolInfo = [&S](StringRef Symbol) {
724 return S.findSymbolInfo(Symbol, "Can not get symbol info");
725 };
726
727 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
728 return S.findSectionInfo(FileName, SectionName);
729 };
730
731 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
732 return S.findStubInfo(FileName, SectionName);
733 };
734
735 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
736 return S.findGOTEntryInfo(FileName, SectionName);
737 };
738
739 RuntimeDyldChecker Checker(
740 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
741 S.TT.isLittleEndian() ? support::little : support::big,
742 Disassembler.get(), InstPrinter.get(), dbgs());
743
744 for (auto &CheckFile : CheckFiles) {
745 auto CheckerFileBuf =
746 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile)));
747 if (!Checker.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf))
748 ExitOnErr(make_error<StringError>(
749 "Some checks in " + CheckFile + " failed", inconvertibleErrorCode()));
750 }
751
752 return Error::success();
753}
754
755static void dumpSessionStats(Session &S) {
756 if (ShowSizes)
Lang Hames4e920e52019-10-04 03:55:26 +0000757 outs() << "Total size of all blocks before pruning: " << S.SizeBeforePruning
758 << "\nTotal size of all blocks after fixups: " << S.SizeAfterFixups
Lang Hames11c8dfa52019-04-20 17:10:34 +0000759 << "\n";
760}
761
762static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000763 return S.ES.lookup(S.JDSearchOrder, EntryPointName);
764}
765
766Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
767 assert(EntryPoint.getAddress() && "Entry point address should not be null");
768
769 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000770 auto PNStorage = std::make_unique<char[]>(strlen(JITProgramName) + 1);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000771 strcpy(PNStorage.get(), JITProgramName);
772
773 std::vector<const char *> EntryPointArgs;
774 EntryPointArgs.push_back(PNStorage.get());
Lang Hamesd959a602019-04-24 17:23:05 +0000775 for (auto &InputArg : InputArgv)
776 EntryPointArgs.push_back(InputArg.data());
Lang Hames11c8dfa52019-04-20 17:10:34 +0000777 EntryPointArgs.push_back(nullptr);
778
779 using MainTy = int (*)(int, const char *[]);
780 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
781
782 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
783}
784
Lang Hames200415c2019-09-04 18:38:29 +0000785struct JITLinkTimers {
Lang Hames41adc372019-09-04 20:26:26 +0000786 TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"};
787 Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG};
788 Timer LinkTimer{"link", "time to link object files", JITLinkTG};
789 Timer RunTimer{"run", "time to execute jitlink'd code", JITLinkTG};
Lang Hames200415c2019-09-04 18:38:29 +0000790};
791
Lang Hames11c8dfa52019-04-20 17:10:34 +0000792int main(int argc, char *argv[]) {
793 InitLLVM X(argc, argv);
794
795 InitializeAllTargetInfos();
796 InitializeAllTargetMCs();
797 InitializeAllDisassemblers();
798
799 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
800 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
801
Lang Hames200415c2019-09-04 18:38:29 +0000802 /// If timers are enabled, create a JITLinkTimers instance.
803 std::unique_ptr<JITLinkTimers> Timers =
804 ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
805
Lang Hames11c8dfa52019-04-20 17:10:34 +0000806 Session S(getFirstFileTriple());
807
Lang Hamesd959a602019-04-24 17:23:05 +0000808 ExitOnErr(sanitizeArguments(S));
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000809
Lang Hames11c8dfa52019-04-20 17:10:34 +0000810 if (!NoProcessSymbols)
811 ExitOnErr(loadProcessSymbols(S));
812 ExitOnErr(loadDylibs());
813
Lang Hames11c8dfa52019-04-20 17:10:34 +0000814
Lang Hames6fd39602019-08-27 15:51:19 +0000815 {
Lang Hames200415c2019-09-04 18:38:29 +0000816 TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000817 ExitOnErr(loadObjects(S));
Lang Hames6fd39602019-08-27 15:51:19 +0000818 }
819
820 JITEvaluatedSymbol EntryPoint = 0;
821 {
Lang Hames200415c2019-09-04 18:38:29 +0000822 TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000823 EntryPoint = ExitOnErr(getMainEntryPoint(S));
Lang Hames6fd39602019-08-27 15:51:19 +0000824 }
Lang Hames11c8dfa52019-04-20 17:10:34 +0000825
826 if (ShowAddrs)
827 S.dumpSessionInfo(outs());
828
829 ExitOnErr(runChecks(S));
830
831 dumpSessionStats(S);
832
833 if (NoExec)
834 return 0;
835
Lang Hames6fd39602019-08-27 15:51:19 +0000836 int Result = 0;
837 {
Lang Hames200415c2019-09-04 18:38:29 +0000838 TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
Lang Hames6fd39602019-08-27 15:51:19 +0000839 Result = ExitOnErr(runEntryPoint(S, EntryPoint));
Lang Hames6fd39602019-08-27 15:51:19 +0000840 }
841
Lang Hames6fd39602019-08-27 15:51:19 +0000842 return Result;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000843}