1059 lines · cpp
1//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This is a testing tool for use with the MC-JIT LLVM components.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/StringMap.h"14#include "llvm/DebugInfo/DIContext.h"15#include "llvm/DebugInfo/DWARF/DWARFContext.h"16#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"17#include "llvm/ExecutionEngine/RuntimeDyld.h"18#include "llvm/ExecutionEngine/RuntimeDyldChecker.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/MC/MCTargetOptions.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Object/SymbolSize.h"29#include "llvm/Support/CommandLine.h"30#include "llvm/Support/DynamicLibrary.h"31#include "llvm/Support/FileSystem.h"32#include "llvm/Support/InitLLVM.h"33#include "llvm/Support/MSVCErrorWorkarounds.h"34#include "llvm/Support/Memory.h"35#include "llvm/Support/MemoryBuffer.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/TargetSelect.h"38#include "llvm/Support/Timer.h"39#include "llvm/Support/raw_ostream.h"40 41#include <future>42#include <list>43 44using namespace llvm;45using namespace llvm::object;46 47static cl::OptionCategory RTDyldCategory("RTDyld Options");48 49static cl::list<std::string> InputFileList(cl::Positional,50 cl::desc("<input files>"),51 cl::cat(RTDyldCategory));52 53enum ActionType {54 AC_Execute,55 AC_PrintObjectLineInfo,56 AC_PrintLineInfo,57 AC_PrintDebugLineInfo,58 AC_Verify59};60 61static cl::opt<ActionType> Action(62 cl::desc("Action to perform:"), cl::init(AC_Execute),63 cl::values(64 clEnumValN(AC_Execute, "execute",65 "Load, link, and execute the inputs."),66 clEnumValN(AC_PrintLineInfo, "printline",67 "Load, link, and print line information for each function."),68 clEnumValN(AC_PrintDebugLineInfo, "printdebugline",69 "Load, link, and print line information for each function "70 "using the debug object"),71 clEnumValN(AC_PrintObjectLineInfo, "printobjline",72 "Like -printlineinfo but does not load the object first"),73 clEnumValN(AC_Verify, "verify",74 "Load, link and verify the resulting memory image.")),75 cl::cat(RTDyldCategory));76 77static cl::opt<std::string>78 EntryPoint("entry", cl::desc("Function to call as entry point."),79 cl::init("_main"), cl::cat(RTDyldCategory));80 81static cl::list<std::string> Dylibs("dylib", cl::desc("Add library."),82 cl::cat(RTDyldCategory));83 84static cl::list<std::string> InputArgv("args", cl::Positional,85 cl::desc("<program arguments>..."),86 cl::PositionalEatsArgs,87 cl::cat(RTDyldCategory));88 89static cl::opt<std::string>90 TripleName("triple", cl::desc("Target triple for disassembler"),91 cl::cat(RTDyldCategory));92 93static cl::opt<std::string>94 MCPU("mcpu",95 cl::desc("Target a specific cpu type (-mcpu=help for details)"),96 cl::value_desc("cpu-name"), cl::init(""), cl::cat(RTDyldCategory));97 98static cl::list<std::string>99 CheckFiles("check",100 cl::desc("File containing RuntimeDyld verifier checks."),101 cl::cat(RTDyldCategory));102 103static cl::opt<uint64_t>104 PreallocMemory("preallocate",105 cl::desc("Allocate memory upfront rather than on-demand"),106 cl::init(0), cl::cat(RTDyldCategory));107 108static cl::opt<uint64_t> TargetAddrStart(109 "target-addr-start",110 cl::desc("For -verify only: start of phony target address "111 "range."),112 cl::init(4096), // Start at "page 1" - no allocating at "null".113 cl::Hidden, cl::cat(RTDyldCategory));114 115static cl::opt<uint64_t> TargetAddrEnd(116 "target-addr-end",117 cl::desc("For -verify only: end of phony target address range."),118 cl::init(~0ULL), cl::Hidden, cl::cat(RTDyldCategory));119 120static cl::opt<uint64_t> TargetSectionSep(121 "target-section-sep",122 cl::desc("For -verify only: Separation between sections in "123 "phony target address space."),124 cl::init(0), cl::Hidden, cl::cat(RTDyldCategory));125 126static cl::list<std::string>127 SpecificSectionMappings("map-section",128 cl::desc("For -verify only: Map a section to a "129 "specific address."),130 cl::Hidden, cl::cat(RTDyldCategory));131 132static cl::list<std::string> DummySymbolMappings(133 "dummy-extern",134 cl::desc("For -verify only: Inject a symbol into the extern "135 "symbol table."),136 cl::Hidden, cl::cat(RTDyldCategory));137 138static cl::opt<bool> PrintAllocationRequests(139 "print-alloc-requests",140 cl::desc("Print allocation requests made to the memory "141 "manager by RuntimeDyld"),142 cl::Hidden, cl::cat(RTDyldCategory));143 144static cl::opt<bool> ShowTimes("show-times",145 cl::desc("Show times for llvm-rtdyld phases"),146 cl::init(false), cl::cat(RTDyldCategory));147 148ExitOnError ExitOnErr;149 150struct RTDyldTimers {151 TimerGroup RTDyldTG{"llvm-rtdyld timers", "timers for llvm-rtdyld phases"};152 Timer LoadObjectsTimer{"load", "time to load/add object files", RTDyldTG};153 Timer LinkTimer{"link", "time to link object files", RTDyldTG};154 Timer RunTimer{"run", "time to execute jitlink'd code", RTDyldTG};155};156 157std::unique_ptr<RTDyldTimers> Timers;158 159/* *** */160 161using SectionIDMap = StringMap<unsigned>;162using FileToSectionIDMap = StringMap<SectionIDMap>;163 164void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) {165 for (const auto &KV : FileToSecIDMap) {166 llvm::dbgs() << "In " << KV.first() << "\n";167 for (auto &KV2 : KV.second)168 llvm::dbgs() << " \"" << KV2.first() << "\" -> " << KV2.second << "\n";169 }170}171 172Expected<unsigned> getSectionId(const FileToSectionIDMap &FileToSecIDMap,173 StringRef FileName, StringRef SectionName) {174 auto I = FileToSecIDMap.find(FileName);175 if (I == FileToSecIDMap.end())176 return make_error<StringError>("No file named " + FileName,177 inconvertibleErrorCode());178 auto &SectionIDs = I->second;179 auto J = SectionIDs.find(SectionName);180 if (J == SectionIDs.end())181 return make_error<StringError>("No section named \"" + SectionName +182 "\" in file " + FileName,183 inconvertibleErrorCode());184 return J->second;185}186 187// A trivial memory manager that doesn't do anything fancy, just uses the188// support library allocation routines directly.189class TrivialMemoryManager : public RTDyldMemoryManager {190public:191 struct SectionInfo {192 SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID)193 : Name(std::string(Name)), MB(std::move(MB)), SectionID(SectionID) {}194 std::string Name;195 sys::MemoryBlock MB;196 unsigned SectionID = ~0U;197 };198 199 SmallVector<SectionInfo, 16> FunctionMemory;200 SmallVector<SectionInfo, 16> DataMemory;201 202 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,203 unsigned SectionID,204 StringRef SectionName) override;205 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,206 unsigned SectionID, StringRef SectionName,207 bool IsReadOnly) override;208 TrivialMemoryManager::TLSSection209 allocateTLSSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,210 StringRef SectionName) override;211 212 /// If non null, records subsequent Name -> SectionID mappings.213 void setSectionIDsMap(SectionIDMap *SecIDMap) {214 this->SecIDMap = SecIDMap;215 }216 217 void *getPointerToNamedFunction(const std::string &Name,218 bool AbortOnFailure = true) override {219 return nullptr;220 }221 222 bool finalizeMemory(std::string *ErrMsg) override { return false; }223 224 void addDummySymbol(const std::string &Name, uint64_t Addr) {225 DummyExterns[Name] = Addr;226 }227 228 JITSymbol findSymbol(const std::string &Name) override {229 auto I = DummyExterns.find(Name);230 231 if (I != DummyExterns.end())232 return JITSymbol(I->second, JITSymbolFlags::Exported);233 234 if (auto Sym = RTDyldMemoryManager::findSymbol(Name))235 return Sym;236 else if (auto Err = Sym.takeError())237 ExitOnErr(std::move(Err));238 else239 ExitOnErr(make_error<StringError>("Could not find definition for \"" +240 Name + "\"",241 inconvertibleErrorCode()));242 llvm_unreachable("Should have returned or exited by now");243 }244 245 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,246 size_t Size) override {}247 void deregisterEHFrames() override {}248 249 void preallocateSlab(uint64_t Size) {250 std::error_code EC;251 sys::MemoryBlock MB =252 sys::Memory::allocateMappedMemory(Size, nullptr,253 sys::Memory::MF_READ |254 sys::Memory::MF_WRITE,255 EC);256 if (!MB.base())257 report_fatal_error(Twine("Can't allocate enough memory: ") +258 EC.message());259 260 PreallocSlab = MB;261 UsePreallocation = true;262 SlabSize = Size;263 }264 265 uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode,266 StringRef SectionName, unsigned SectionID) {267 Size = alignTo(Size, Alignment);268 if (CurrentSlabOffset + Size > SlabSize)269 report_fatal_error("Can't allocate enough memory. Tune --preallocate");270 271 uintptr_t OldSlabOffset = CurrentSlabOffset;272 sys::MemoryBlock MB((void *)OldSlabOffset, Size);273 if (isCode)274 FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));275 else276 DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));277 CurrentSlabOffset += Size;278 return (uint8_t*)OldSlabOffset;279 }280 281private:282 std::map<std::string, uint64_t> DummyExterns;283 sys::MemoryBlock PreallocSlab;284 bool UsePreallocation = false;285 uintptr_t SlabSize = 0;286 uintptr_t CurrentSlabOffset = 0;287 SectionIDMap *SecIDMap = nullptr;288#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)289 unsigned UsedTLSStorage = 0;290#endif291};292 293uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,294 unsigned Alignment,295 unsigned SectionID,296 StringRef SectionName) {297 if (PrintAllocationRequests)298 outs() << "allocateCodeSection(Size = " << Size << ", Alignment = "299 << Alignment << ", SectionName = " << SectionName << ")\n";300 301 if (SecIDMap)302 (*SecIDMap)[SectionName] = SectionID;303 304 if (UsePreallocation)305 return allocateFromSlab(Size, Alignment, true /* isCode */,306 SectionName, SectionID);307 308 std::error_code EC;309 sys::MemoryBlock MB =310 sys::Memory::allocateMappedMemory(Size, nullptr,311 sys::Memory::MF_READ |312 sys::Memory::MF_WRITE,313 EC);314 if (!MB.base())315 report_fatal_error(Twine("MemoryManager allocation failed: ") +316 EC.message());317 FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));318 return (uint8_t*)MB.base();319}320 321uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,322 unsigned Alignment,323 unsigned SectionID,324 StringRef SectionName,325 bool IsReadOnly) {326 if (PrintAllocationRequests)327 outs() << "allocateDataSection(Size = " << Size << ", Alignment = "328 << Alignment << ", SectionName = " << SectionName << ")\n";329 330 if (SecIDMap)331 (*SecIDMap)[SectionName] = SectionID;332 333 if (UsePreallocation)334 return allocateFromSlab(Size, Alignment, false /* isCode */, SectionName,335 SectionID);336 337 std::error_code EC;338 sys::MemoryBlock MB =339 sys::Memory::allocateMappedMemory(Size, nullptr,340 sys::Memory::MF_READ |341 sys::Memory::MF_WRITE,342 EC);343 if (!MB.base())344 report_fatal_error(Twine("MemoryManager allocation failed: ") +345 EC.message());346 DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));347 return (uint8_t*)MB.base();348}349 350// In case the execution needs TLS storage, we define a very small TLS memory351// area here that will be used in allocateTLSSection().352#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)353extern "C" {354alignas(16) __attribute__((visibility("hidden"), tls_model("initial-exec"),355 used)) thread_local char LLVMRTDyldTLSSpace[16];356}357#endif358 359TrivialMemoryManager::TLSSection360TrivialMemoryManager::allocateTLSSection(uintptr_t Size, unsigned Alignment,361 unsigned SectionID,362 StringRef SectionName) {363#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)364 if (Size + UsedTLSStorage > sizeof(LLVMRTDyldTLSSpace)) {365 return {};366 }367 368 // Get the offset of the TLSSpace in the TLS block by using a tpoff369 // relocation here.370 int64_t TLSOffset;371 asm("leaq LLVMRTDyldTLSSpace@tpoff, %0" : "=r"(TLSOffset));372 373 TLSSection Section;374 // We use the storage directly as the initialization image. This means that375 // when a new thread is spawned after this allocation, it will not be376 // initialized correctly. This means, llvm-rtdyld will only support TLS in a377 // single thread.378 Section.InitializationImage =379 reinterpret_cast<uint8_t *>(LLVMRTDyldTLSSpace + UsedTLSStorage);380 Section.Offset = TLSOffset + UsedTLSStorage;381 382 UsedTLSStorage += Size;383 384 return Section;385#else386 return {};387#endif388}389 390static const char *ProgramName;391 392static void ErrorAndExit(const Twine &Msg) {393 errs() << ProgramName << ": error: " << Msg << "\n";394 exit(1);395}396 397static void loadDylibs() {398 for (const std::string &Dylib : Dylibs) {399 if (!sys::fs::is_regular_file(Dylib))400 report_fatal_error(Twine("Dylib not found: '") + Dylib + "'.");401 std::string ErrMsg;402 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))403 report_fatal_error(Twine("Error loading '") + Dylib + "': " + ErrMsg);404 }405}406 407/* *** */408 409static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {410 assert(LoadObjects || !UseDebugObj);411 412 // Load any dylibs requested on the command line.413 loadDylibs();414 415 // If we don't have any input files, read from stdin.416 if (!InputFileList.size())417 InputFileList.push_back("-");418 for (auto &File : InputFileList) {419 // Instantiate a dynamic linker.420 TrivialMemoryManager MemMgr;421 RuntimeDyld Dyld(MemMgr, MemMgr);422 423 // Load the input memory buffer.424 425 ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =426 MemoryBuffer::getFileOrSTDIN(File);427 if (std::error_code EC = InputBuffer.getError())428 ErrorAndExit("unable to read input: '" + EC.message() + "'");429 430 Expected<std::unique_ptr<ObjectFile>> MaybeObj(431 ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));432 433 if (!MaybeObj) {434 std::string Buf;435 raw_string_ostream OS(Buf);436 logAllUnhandledErrors(MaybeObj.takeError(), OS);437 OS.flush();438 ErrorAndExit("unable to create object file: '" + Buf + "'");439 }440 441 ObjectFile &Obj = **MaybeObj;442 443 OwningBinary<ObjectFile> DebugObj;444 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;445 ObjectFile *SymbolObj = &Obj;446 if (LoadObjects) {447 // Load the object file448 LoadedObjInfo =449 Dyld.loadObject(Obj);450 451 if (Dyld.hasError())452 ErrorAndExit(Dyld.getErrorString());453 454 // Resolve all the relocations we can.455 Dyld.resolveRelocations();456 457 if (UseDebugObj) {458 DebugObj = LoadedObjInfo->getObjectForDebug(Obj);459 SymbolObj = DebugObj.getBinary();460 LoadedObjInfo.reset();461 }462 }463 464 std::unique_ptr<DIContext> Context = DWARFContext::create(465 *SymbolObj, DWARFContext::ProcessDebugRelocations::Process,466 LoadedObjInfo.get());467 468 std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =469 object::computeSymbolSizes(*SymbolObj);470 471 // Use symbol info to iterate functions in the object.472 for (const auto &P : SymAddr) {473 object::SymbolRef Sym = P.first;474 Expected<SymbolRef::Type> TypeOrErr = Sym.getType();475 if (!TypeOrErr) {476 // TODO: Actually report errors helpfully.477 consumeError(TypeOrErr.takeError());478 continue;479 }480 SymbolRef::Type Type = *TypeOrErr;481 if (Type == object::SymbolRef::ST_Function) {482 Expected<StringRef> Name = Sym.getName();483 if (!Name) {484 // TODO: Actually report errors helpfully.485 consumeError(Name.takeError());486 continue;487 }488 Expected<uint64_t> AddrOrErr = Sym.getAddress();489 if (!AddrOrErr) {490 // TODO: Actually report errors helpfully.491 consumeError(AddrOrErr.takeError());492 continue;493 }494 uint64_t Addr = *AddrOrErr;495 496 object::SectionedAddress Address;497 498 uint64_t Size = P.second;499 // If we're not using the debug object, compute the address of the500 // symbol in memory (rather than that in the unrelocated object file)501 // and use that to query the DWARFContext.502 if (!UseDebugObj && LoadObjects) {503 auto SecOrErr = Sym.getSection();504 if (!SecOrErr) {505 // TODO: Actually report errors helpfully.506 consumeError(SecOrErr.takeError());507 continue;508 }509 object::section_iterator Sec = *SecOrErr;510 Address.SectionIndex = Sec->getIndex();511 uint64_t SectionLoadAddress =512 LoadedObjInfo->getSectionLoadAddress(*Sec);513 if (SectionLoadAddress != 0)514 Addr += SectionLoadAddress - Sec->getAddress();515 } else if (auto SecOrErr = Sym.getSection())516 Address.SectionIndex = SecOrErr.get()->getIndex();517 518 outs() << "Function: " << *Name << ", Size = " << Size519 << ", Addr = " << Addr << "\n";520 521 Address.Address = Addr;522 DILineInfoTable Lines =523 Context->getLineInfoForAddressRange(Address, Size);524 for (auto &D : Lines) {525 outs() << " Line info @ " << D.first - Addr << ": "526 << D.second.FileName << ", line:" << D.second.Line << "\n";527 }528 }529 }530 }531 532 return 0;533}534 535static void doPreallocation(TrivialMemoryManager &MemMgr) {536 // Allocate a slab of memory upfront, if required. This is used if537 // we want to test small code models.538 if (static_cast<intptr_t>(PreallocMemory) < 0)539 report_fatal_error("Pre-allocated bytes of memory must be a positive integer.");540 541 // FIXME: Limit the amount of memory that can be preallocated?542 if (PreallocMemory != 0)543 MemMgr.preallocateSlab(PreallocMemory);544}545 546static int executeInput() {547 // Load any dylibs requested on the command line.548 loadDylibs();549 550 // Instantiate a dynamic linker.551 TrivialMemoryManager MemMgr;552 doPreallocation(MemMgr);553 RuntimeDyld Dyld(MemMgr, MemMgr);554 555 // If we don't have any input files, read from stdin.556 if (!InputFileList.size())557 InputFileList.push_back("-");558 {559 TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);560 for (auto &File : InputFileList) {561 // Load the input memory buffer.562 ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =563 MemoryBuffer::getFileOrSTDIN(File);564 if (std::error_code EC = InputBuffer.getError())565 ErrorAndExit("unable to read input: '" + EC.message() + "'");566 Expected<std::unique_ptr<ObjectFile>> MaybeObj(567 ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));568 569 if (!MaybeObj) {570 std::string Buf;571 raw_string_ostream OS(Buf);572 logAllUnhandledErrors(MaybeObj.takeError(), OS);573 OS.flush();574 ErrorAndExit("unable to create object file: '" + Buf + "'");575 }576 577 ObjectFile &Obj = **MaybeObj;578 579 // Load the object file580 Dyld.loadObject(Obj);581 if (Dyld.hasError()) {582 ErrorAndExit(Dyld.getErrorString());583 }584 }585 }586 587 {588 TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);589 // Resove all the relocations we can.590 // FIXME: Error out if there are unresolved relocations.591 Dyld.resolveRelocations();592 }593 594 // Get the address of the entry point (_main by default).595 void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint);596 if (!MainAddress)597 ErrorAndExit("no definition for '" + EntryPoint + "'");598 599 // Invalidate the instruction cache for each loaded function.600 for (auto &FM : MemMgr.FunctionMemory) {601 602 auto &FM_MB = FM.MB;603 604 // Make sure the memory is executable.605 // setExecutable will call InvalidateInstructionCache.606 if (auto EC = sys::Memory::protectMappedMemory(FM_MB,607 sys::Memory::MF_READ |608 sys::Memory::MF_EXEC))609 ErrorAndExit("unable to mark function executable: '" + EC.message() +610 "'");611 }612 613 // Dispatch to _main().614 errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";615 616 int (*Main)(int, const char**) =617 (int(*)(int,const char**)) uintptr_t(MainAddress);618 std::vector<const char *> Argv;619 // Use the name of the first input object module as argv[0] for the target.620 Argv.push_back(InputFileList[0].data());621 for (auto &Arg : InputArgv)622 Argv.push_back(Arg.data());623 Argv.push_back(nullptr);624 int Result = 0;625 {626 TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);627 Result = Main(Argv.size() - 1, Argv.data());628 }629 630 return Result;631}632 633static int checkAllExpressions(RuntimeDyldChecker &Checker) {634 for (const auto& CheckerFileName : CheckFiles) {635 ErrorOr<std::unique_ptr<MemoryBuffer>> CheckerFileBuf =636 MemoryBuffer::getFileOrSTDIN(CheckerFileName);637 if (std::error_code EC = CheckerFileBuf.getError())638 ErrorAndExit("unable to read input '" + CheckerFileName + "': " +639 EC.message());640 641 if (!Checker.checkAllRulesInBuffer("# rtdyld-check:",642 CheckerFileBuf.get().get()))643 ErrorAndExit("some checks in '" + CheckerFileName + "' failed");644 }645 return 0;646}647 648void applySpecificSectionMappings(RuntimeDyld &Dyld,649 const FileToSectionIDMap &FileToSecIDMap) {650 651 for (StringRef Mapping : SpecificSectionMappings) {652 size_t EqualsIdx = Mapping.find_first_of('=');653 std::string SectionIDStr = std::string(Mapping.substr(0, EqualsIdx));654 size_t ComaIdx = Mapping.find_first_of(',');655 656 if (ComaIdx == StringRef::npos)657 report_fatal_error("Invalid section specification '" + Mapping +658 "'. Should be '<file name>,<section name>=<addr>'");659 660 std::string FileName = SectionIDStr.substr(0, ComaIdx);661 std::string SectionName = SectionIDStr.substr(ComaIdx + 1);662 unsigned SectionID =663 ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));664 665 auto* OldAddr = Dyld.getSectionContent(SectionID).data();666 std::string NewAddrStr = std::string(Mapping.substr(EqualsIdx + 1));667 uint64_t NewAddr;668 669 if (StringRef(NewAddrStr).getAsInteger(0, NewAddr))670 report_fatal_error("Invalid section address in mapping '" + Mapping +671 "'.");672 673 Dyld.mapSectionAddress(OldAddr, NewAddr);674 }675}676 677// Scatter sections in all directions!678// Remaps section addresses for -verify mode. The following command line options679// can be used to customize the layout of the memory within the phony target's680// address space:681// -target-addr-start <s> -- Specify where the phony target address range starts.682// -target-addr-end <e> -- Specify where the phony target address range ends.683// -target-section-sep <d> -- Specify how big a gap should be left between the684// end of one section and the start of the next.685// Defaults to zero. Set to something big686// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.687//688static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,689 RuntimeDyld &Dyld,690 TrivialMemoryManager &MemMgr) {691 692 // Set up a work list (section addr/size pairs).693 typedef std::list<const TrivialMemoryManager::SectionInfo*> WorklistT;694 WorklistT Worklist;695 696 for (const auto& CodeSection : MemMgr.FunctionMemory)697 Worklist.push_back(&CodeSection);698 for (const auto& DataSection : MemMgr.DataMemory)699 Worklist.push_back(&DataSection);700 701 // Keep an "already allocated" mapping of section target addresses to sizes.702 // Sections whose address mappings aren't specified on the command line will703 // allocated around the explicitly mapped sections while maintaining the704 // minimum separation.705 std::map<uint64_t, uint64_t> AlreadyAllocated;706 707 // Move the previously applied mappings (whether explicitly specified on the708 // command line, or implicitly set by RuntimeDyld) into the already-allocated709 // map.710 for (WorklistT::iterator I = Worklist.begin(), E = Worklist.end();711 I != E;) {712 WorklistT::iterator Tmp = I;713 ++I;714 715 auto LoadAddr = Dyld.getSectionLoadAddress((*Tmp)->SectionID);716 717 if (LoadAddr != static_cast<uint64_t>(718 reinterpret_cast<uintptr_t>((*Tmp)->MB.base()))) {719 // A section will have a LoadAddr of 0 if it wasn't loaded for whatever720 // reason (e.g. zero byte COFF sections). Don't include those sections in721 // the allocation map.722 if (LoadAddr != 0)723 AlreadyAllocated[LoadAddr] = (*Tmp)->MB.allocatedSize();724 Worklist.erase(Tmp);725 }726 }727 728 // If the -target-addr-end option wasn't explicitly passed, then set it to a729 // sensible default based on the target triple.730 if (TargetAddrEnd.getNumOccurrences() == 0) {731 if (TargetTriple.isArch16Bit())732 TargetAddrEnd = (1ULL << 16) - 1;733 else if (TargetTriple.isArch32Bit())734 TargetAddrEnd = (1ULL << 32) - 1;735 // TargetAddrEnd already has a sensible default for 64-bit systems, so736 // there's nothing to do in the 64-bit case.737 }738 739 // Process any elements remaining in the worklist.740 while (!Worklist.empty()) {741 auto *CurEntry = Worklist.front();742 Worklist.pop_front();743 744 uint64_t NextSectionAddr = TargetAddrStart;745 746 for (const auto &Alloc : AlreadyAllocated)747 if (NextSectionAddr + CurEntry->MB.allocatedSize() + TargetSectionSep <=748 Alloc.first)749 break;750 else751 NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep;752 753 Dyld.mapSectionAddress(CurEntry->MB.base(), NextSectionAddr);754 AlreadyAllocated[NextSectionAddr] = CurEntry->MB.allocatedSize();755 }756 757 // Add dummy symbols to the memory manager.758 for (const auto &Mapping : DummySymbolMappings) {759 size_t EqualsIdx = Mapping.find_first_of('=');760 761 if (EqualsIdx == StringRef::npos)762 report_fatal_error(Twine("Invalid dummy symbol specification '") +763 Mapping + "'. Should be '<symbol name>=<addr>'");764 765 std::string Symbol = Mapping.substr(0, EqualsIdx);766 std::string AddrStr = Mapping.substr(EqualsIdx + 1);767 768 uint64_t Addr;769 if (StringRef(AddrStr).getAsInteger(0, Addr))770 report_fatal_error(Twine("Invalid symbol mapping '") + Mapping + "'.");771 772 MemMgr.addDummySymbol(Symbol, Addr);773 }774}775 776// Load and link the objects specified on the command line, but do not execute777// anything. Instead, attach a RuntimeDyldChecker instance and call it to778// verify the correctness of the linked memory.779static int linkAndVerify() {780 781 // Check for missing triple.782 if (TripleName == "")783 ErrorAndExit("-triple required when running in -verify mode.");784 785 // Look up the target and build the disassembler.786 Triple TheTriple(Triple::normalize(TripleName));787 std::string ErrorStr;788 const Target *TheTarget =789 TargetRegistry::lookupTarget("", TheTriple, ErrorStr);790 if (!TheTarget)791 ErrorAndExit("Error accessing target '" + TripleName + "': " + ErrorStr);792 793 TripleName = TheTriple.getTriple();794 795 std::unique_ptr<MCSubtargetInfo> STI(796 TheTarget->createMCSubtargetInfo(TheTriple, MCPU, ""));797 if (!STI)798 ErrorAndExit("Unable to create subtarget info!");799 800 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));801 if (!MRI)802 ErrorAndExit("Unable to create target register info!");803 804 MCTargetOptions MCOptions;805 std::unique_ptr<MCAsmInfo> MAI(806 TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));807 if (!MAI)808 ErrorAndExit("Unable to create target asm info!");809 810 MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get());811 812 std::unique_ptr<MCDisassembler> Disassembler(813 TheTarget->createMCDisassembler(*STI, Ctx));814 if (!Disassembler)815 ErrorAndExit("Unable to create disassembler!");816 817 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());818 if (!MII)819 ErrorAndExit("Unable to create target instruction info!");820 821 std::unique_ptr<MCInstPrinter> InstPrinter(822 TheTarget->createMCInstPrinter(TheTriple, 0, *MAI, *MII, *MRI));823 824 // Load any dylibs requested on the command line.825 loadDylibs();826 827 // Instantiate a dynamic linker.828 TrivialMemoryManager MemMgr;829 doPreallocation(MemMgr);830 831 struct StubID {832 unsigned SectionID;833 uint32_t Offset;834 };835 using StubInfos = StringMap<StubID>;836 using StubContainers = StringMap<StubInfos>;837 838 StubContainers StubMap;839 RuntimeDyld Dyld(MemMgr, MemMgr);840 Dyld.setProcessAllSections(true);841 842 Dyld.setNotifyStubEmitted([&StubMap](StringRef FilePath,843 StringRef SectionName,844 StringRef SymbolName, unsigned SectionID,845 uint32_t StubOffset) {846 std::string ContainerName =847 (sys::path::filename(FilePath) + "/" + SectionName).str();848 StubMap[ContainerName][SymbolName] = {SectionID, StubOffset};849 });850 851 auto GetSymbolInfo =852 [&Dyld, &MemMgr](853 StringRef Symbol) -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {854 RuntimeDyldChecker::MemoryRegionInfo SymInfo;855 856 // First get the target address.857 if (auto InternalSymbol = Dyld.getSymbol(Symbol))858 SymInfo.setTargetAddress(InternalSymbol.getAddress());859 else {860 // Symbol not found in RuntimeDyld. Fall back to external lookup.861#ifdef _MSC_VER862 using ExpectedLookupResult =863 MSVCPExpected<JITSymbolResolver::LookupResult>;864#else865 using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>;866#endif867 868 auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>();869 auto ResultF = ResultP->get_future();870 871 MemMgr.lookup(JITSymbolResolver::LookupSet({Symbol}),872 [=](Expected<JITSymbolResolver::LookupResult> Result) {873 ResultP->set_value(std::move(Result));874 });875 876 auto Result = ResultF.get();877 if (!Result)878 return Result.takeError();879 880 auto I = Result->find(Symbol);881 assert(I != Result->end() &&882 "Expected symbol address if no error occurred");883 SymInfo.setTargetAddress(I->second.getAddress());884 }885 886 // Now find the symbol content if possible (otherwise leave content as a887 // default-constructed StringRef).888 if (auto *SymAddr = Dyld.getSymbolLocalAddress(Symbol)) {889 unsigned SectionID = Dyld.getSymbolSectionID(Symbol);890 if (SectionID != ~0U) {891 char *CSymAddr = static_cast<char *>(SymAddr);892 StringRef SecContent = Dyld.getSectionContent(SectionID);893 uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data());894 SymInfo.setContent(ArrayRef<char>(CSymAddr, SymSize));895 SymInfo.setTargetFlags(896 Dyld.getSymbol(Symbol).getFlags().getTargetFlags());897 }898 }899 return SymInfo;900 };901 902 auto IsSymbolValid = [&Dyld, GetSymbolInfo](StringRef Symbol) {903 if (Dyld.getSymbol(Symbol))904 return true;905 auto SymInfo = GetSymbolInfo(Symbol);906 if (!SymInfo) {907 logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");908 return false;909 }910 return SymInfo->getTargetAddress() != 0;911 };912 913 FileToSectionIDMap FileToSecIDMap;914 915 auto GetSectionInfo = [&Dyld, &FileToSecIDMap](StringRef FileName,916 StringRef SectionName)917 -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {918 auto SectionID = getSectionId(FileToSecIDMap, FileName, SectionName);919 if (!SectionID)920 return SectionID.takeError();921 RuntimeDyldChecker::MemoryRegionInfo SecInfo;922 SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(*SectionID));923 StringRef SecContent = Dyld.getSectionContent(*SectionID);924 SecInfo.setContent(ArrayRef<char>(SecContent));925 return SecInfo;926 };927 928 auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer,929 StringRef SymbolName,930 StringRef KindNameFilter)931 -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {932 auto SMIt = StubMap.find(StubContainer);933 if (SMIt == StubMap.end())934 return make_error<StringError>("Stub container not found: " +935 StubContainer,936 inconvertibleErrorCode());937 auto It = SMIt->second.find(SymbolName);938 if (It == SMIt->second.end())939 return make_error<StringError>("Symbol name " + SymbolName +940 " in stub container " + StubContainer,941 inconvertibleErrorCode());942 auto &SI = It->second;943 RuntimeDyldChecker::MemoryRegionInfo StubMemInfo;944 StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SI.SectionID) +945 SI.Offset);946 StringRef SecContent =947 Dyld.getSectionContent(SI.SectionID).substr(SI.Offset);948 StubMemInfo.setContent(ArrayRef<char>(SecContent));949 return StubMemInfo;950 };951 952 auto GetGOTInfo = [&GetStubInfo](StringRef StubContainer,953 StringRef SymbolName) {954 return GetStubInfo(StubContainer, SymbolName, "");955 };956 957 // We will initialize this below once we have the first object file and can958 // know the endianness.959 std::unique_ptr<RuntimeDyldChecker> Checker;960 961 // If we don't have any input files, read from stdin.962 if (!InputFileList.size())963 InputFileList.push_back("-");964 for (auto &InputFile : InputFileList) {965 // Load the input memory buffer.966 ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =967 MemoryBuffer::getFileOrSTDIN(InputFile);968 969 if (std::error_code EC = InputBuffer.getError())970 ErrorAndExit("unable to read input: '" + EC.message() + "'");971 972 Expected<std::unique_ptr<ObjectFile>> MaybeObj(973 ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));974 975 if (!MaybeObj) {976 std::string Buf;977 raw_string_ostream OS(Buf);978 logAllUnhandledErrors(MaybeObj.takeError(), OS);979 OS.flush();980 ErrorAndExit("unable to create object file: '" + Buf + "'");981 }982 983 ObjectFile &Obj = **MaybeObj;984 985 if (!Checker)986 Checker = std::make_unique<RuntimeDyldChecker>(987 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,988 Obj.isLittleEndian() ? llvm::endianness::little989 : llvm::endianness::big,990 TheTriple, MCPU, SubtargetFeatures(), dbgs());991 992 auto FileName = sys::path::filename(InputFile);993 MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);994 995 // Load the object file996 Dyld.loadObject(Obj);997 if (Dyld.hasError()) {998 ErrorAndExit(Dyld.getErrorString());999 }1000 }1001 1002 // Re-map the section addresses into the phony target address space and add1003 // dummy symbols.1004 applySpecificSectionMappings(Dyld, FileToSecIDMap);1005 remapSectionsAndSymbols(TheTriple, Dyld, MemMgr);1006 1007 // Resolve all the relocations we can.1008 Dyld.resolveRelocations();1009 1010 // Register EH frames.1011 Dyld.registerEHFrames();1012 1013 int ErrorCode = checkAllExpressions(*Checker);1014 if (Dyld.hasError())1015 ErrorAndExit("RTDyld reported an error applying relocations:\n " +1016 Dyld.getErrorString());1017 1018 return ErrorCode;1019}1020 1021int main(int argc, char **argv) {1022 InitLLVM X(argc, argv);1023 ProgramName = argv[0];1024 1025 llvm::InitializeAllTargetInfos();1026 llvm::InitializeAllTargetMCs();1027 llvm::InitializeAllDisassemblers();1028 1029 cl::HideUnrelatedOptions({&RTDyldCategory, &getColorCategory()});1030 cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");1031 1032 ExitOnErr.setBanner(std::string(argv[0]) + ": ");1033 1034 Timers = ShowTimes ? std::make_unique<RTDyldTimers>() : nullptr;1035 1036 int Result = 0;1037 switch (Action) {1038 case AC_Execute:1039 Result = executeInput();1040 break;1041 case AC_PrintDebugLineInfo:1042 Result =1043 printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ true);1044 break;1045 case AC_PrintLineInfo:1046 Result =1047 printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ false);1048 break;1049 case AC_PrintObjectLineInfo:1050 Result =1051 printLineInfoForInput(/* LoadObjects */ false, /* UseDebugObj */ false);1052 break;1053 case AC_Verify:1054 Result = linkAndVerify();1055 break;1056 }1057 return Result;1058}1059