Path: blob/main/contrib/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
35231 views
//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This is a testing tool for use with the MC-JIT LLVM components.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ADT/StringMap.h"13#include "llvm/DebugInfo/DIContext.h"14#include "llvm/DebugInfo/DWARF/DWARFContext.h"15#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"16#include "llvm/ExecutionEngine/RuntimeDyld.h"17#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"18#include "llvm/MC/MCAsmInfo.h"19#include "llvm/MC/MCContext.h"20#include "llvm/MC/MCDisassembler/MCDisassembler.h"21#include "llvm/MC/MCInstPrinter.h"22#include "llvm/MC/MCInstrInfo.h"23#include "llvm/MC/MCRegisterInfo.h"24#include "llvm/MC/MCSubtargetInfo.h"25#include "llvm/MC/MCTargetOptions.h"26#include "llvm/MC/TargetRegistry.h"27#include "llvm/Object/SymbolSize.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/DynamicLibrary.h"30#include "llvm/Support/FileSystem.h"31#include "llvm/Support/InitLLVM.h"32#include "llvm/Support/MSVCErrorWorkarounds.h"33#include "llvm/Support/Memory.h"34#include "llvm/Support/MemoryBuffer.h"35#include "llvm/Support/Path.h"36#include "llvm/Support/TargetSelect.h"37#include "llvm/Support/Timer.h"38#include "llvm/Support/raw_ostream.h"3940#include <future>41#include <list>4243using namespace llvm;44using namespace llvm::object;4546static cl::OptionCategory RTDyldCategory("RTDyld Options");4748static cl::list<std::string> InputFileList(cl::Positional,49cl::desc("<input files>"),50cl::cat(RTDyldCategory));5152enum ActionType {53AC_Execute,54AC_PrintObjectLineInfo,55AC_PrintLineInfo,56AC_PrintDebugLineInfo,57AC_Verify58};5960static cl::opt<ActionType> Action(61cl::desc("Action to perform:"), cl::init(AC_Execute),62cl::values(63clEnumValN(AC_Execute, "execute",64"Load, link, and execute the inputs."),65clEnumValN(AC_PrintLineInfo, "printline",66"Load, link, and print line information for each function."),67clEnumValN(AC_PrintDebugLineInfo, "printdebugline",68"Load, link, and print line information for each function "69"using the debug object"),70clEnumValN(AC_PrintObjectLineInfo, "printobjline",71"Like -printlineinfo but does not load the object first"),72clEnumValN(AC_Verify, "verify",73"Load, link and verify the resulting memory image.")),74cl::cat(RTDyldCategory));7576static cl::opt<std::string>77EntryPoint("entry", cl::desc("Function to call as entry point."),78cl::init("_main"), cl::cat(RTDyldCategory));7980static cl::list<std::string> Dylibs("dylib", cl::desc("Add library."),81cl::cat(RTDyldCategory));8283static cl::list<std::string> InputArgv("args", cl::Positional,84cl::desc("<program arguments>..."),85cl::PositionalEatsArgs,86cl::cat(RTDyldCategory));8788static cl::opt<std::string>89TripleName("triple", cl::desc("Target triple for disassembler"),90cl::cat(RTDyldCategory));9192static cl::opt<std::string>93MCPU("mcpu",94cl::desc("Target a specific cpu type (-mcpu=help for details)"),95cl::value_desc("cpu-name"), cl::init(""), cl::cat(RTDyldCategory));9697static cl::list<std::string>98CheckFiles("check",99cl::desc("File containing RuntimeDyld verifier checks."),100cl::cat(RTDyldCategory));101102static cl::opt<uint64_t>103PreallocMemory("preallocate",104cl::desc("Allocate memory upfront rather than on-demand"),105cl::init(0), cl::cat(RTDyldCategory));106107static cl::opt<uint64_t> TargetAddrStart(108"target-addr-start",109cl::desc("For -verify only: start of phony target address "110"range."),111cl::init(4096), // Start at "page 1" - no allocating at "null".112cl::Hidden, cl::cat(RTDyldCategory));113114static cl::opt<uint64_t> TargetAddrEnd(115"target-addr-end",116cl::desc("For -verify only: end of phony target address range."),117cl::init(~0ULL), cl::Hidden, cl::cat(RTDyldCategory));118119static cl::opt<uint64_t> TargetSectionSep(120"target-section-sep",121cl::desc("For -verify only: Separation between sections in "122"phony target address space."),123cl::init(0), cl::Hidden, cl::cat(RTDyldCategory));124125static cl::list<std::string>126SpecificSectionMappings("map-section",127cl::desc("For -verify only: Map a section to a "128"specific address."),129cl::Hidden, cl::cat(RTDyldCategory));130131static cl::list<std::string> DummySymbolMappings(132"dummy-extern",133cl::desc("For -verify only: Inject a symbol into the extern "134"symbol table."),135cl::Hidden, cl::cat(RTDyldCategory));136137static cl::opt<bool> PrintAllocationRequests(138"print-alloc-requests",139cl::desc("Print allocation requests made to the memory "140"manager by RuntimeDyld"),141cl::Hidden, cl::cat(RTDyldCategory));142143static cl::opt<bool> ShowTimes("show-times",144cl::desc("Show times for llvm-rtdyld phases"),145cl::init(false), cl::cat(RTDyldCategory));146147ExitOnError ExitOnErr;148149struct RTDyldTimers {150TimerGroup RTDyldTG{"llvm-rtdyld timers", "timers for llvm-rtdyld phases"};151Timer LoadObjectsTimer{"load", "time to load/add object files", RTDyldTG};152Timer LinkTimer{"link", "time to link object files", RTDyldTG};153Timer RunTimer{"run", "time to execute jitlink'd code", RTDyldTG};154};155156std::unique_ptr<RTDyldTimers> Timers;157158/* *** */159160using SectionIDMap = StringMap<unsigned>;161using FileToSectionIDMap = StringMap<SectionIDMap>;162163void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) {164for (const auto &KV : FileToSecIDMap) {165llvm::dbgs() << "In " << KV.first() << "\n";166for (auto &KV2 : KV.second)167llvm::dbgs() << " \"" << KV2.first() << "\" -> " << KV2.second << "\n";168}169}170171Expected<unsigned> getSectionId(const FileToSectionIDMap &FileToSecIDMap,172StringRef FileName, StringRef SectionName) {173auto I = FileToSecIDMap.find(FileName);174if (I == FileToSecIDMap.end())175return make_error<StringError>("No file named " + FileName,176inconvertibleErrorCode());177auto &SectionIDs = I->second;178auto J = SectionIDs.find(SectionName);179if (J == SectionIDs.end())180return make_error<StringError>("No section named \"" + SectionName +181"\" in file " + FileName,182inconvertibleErrorCode());183return J->second;184}185186// A trivial memory manager that doesn't do anything fancy, just uses the187// support library allocation routines directly.188class TrivialMemoryManager : public RTDyldMemoryManager {189public:190struct SectionInfo {191SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID)192: Name(std::string(Name)), MB(std::move(MB)), SectionID(SectionID) {}193std::string Name;194sys::MemoryBlock MB;195unsigned SectionID = ~0U;196};197198SmallVector<SectionInfo, 16> FunctionMemory;199SmallVector<SectionInfo, 16> DataMemory;200201uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,202unsigned SectionID,203StringRef SectionName) override;204uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,205unsigned SectionID, StringRef SectionName,206bool IsReadOnly) override;207TrivialMemoryManager::TLSSection208allocateTLSSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,209StringRef SectionName) override;210211/// If non null, records subsequent Name -> SectionID mappings.212void setSectionIDsMap(SectionIDMap *SecIDMap) {213this->SecIDMap = SecIDMap;214}215216void *getPointerToNamedFunction(const std::string &Name,217bool AbortOnFailure = true) override {218return nullptr;219}220221bool finalizeMemory(std::string *ErrMsg) override { return false; }222223void addDummySymbol(const std::string &Name, uint64_t Addr) {224DummyExterns[Name] = Addr;225}226227JITSymbol findSymbol(const std::string &Name) override {228auto I = DummyExterns.find(Name);229230if (I != DummyExterns.end())231return JITSymbol(I->second, JITSymbolFlags::Exported);232233if (auto Sym = RTDyldMemoryManager::findSymbol(Name))234return Sym;235else if (auto Err = Sym.takeError())236ExitOnErr(std::move(Err));237else238ExitOnErr(make_error<StringError>("Could not find definition for \"" +239Name + "\"",240inconvertibleErrorCode()));241llvm_unreachable("Should have returned or exited by now");242}243244void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,245size_t Size) override {}246void deregisterEHFrames() override {}247248void preallocateSlab(uint64_t Size) {249std::error_code EC;250sys::MemoryBlock MB =251sys::Memory::allocateMappedMemory(Size, nullptr,252sys::Memory::MF_READ |253sys::Memory::MF_WRITE,254EC);255if (!MB.base())256report_fatal_error(Twine("Can't allocate enough memory: ") +257EC.message());258259PreallocSlab = MB;260UsePreallocation = true;261SlabSize = Size;262}263264uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode,265StringRef SectionName, unsigned SectionID) {266Size = alignTo(Size, Alignment);267if (CurrentSlabOffset + Size > SlabSize)268report_fatal_error("Can't allocate enough memory. Tune --preallocate");269270uintptr_t OldSlabOffset = CurrentSlabOffset;271sys::MemoryBlock MB((void *)OldSlabOffset, Size);272if (isCode)273FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));274else275DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));276CurrentSlabOffset += Size;277return (uint8_t*)OldSlabOffset;278}279280private:281std::map<std::string, uint64_t> DummyExterns;282sys::MemoryBlock PreallocSlab;283bool UsePreallocation = false;284uintptr_t SlabSize = 0;285uintptr_t CurrentSlabOffset = 0;286SectionIDMap *SecIDMap = nullptr;287#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)288unsigned UsedTLSStorage = 0;289#endif290};291292uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,293unsigned Alignment,294unsigned SectionID,295StringRef SectionName) {296if (PrintAllocationRequests)297outs() << "allocateCodeSection(Size = " << Size << ", Alignment = "298<< Alignment << ", SectionName = " << SectionName << ")\n";299300if (SecIDMap)301(*SecIDMap)[SectionName] = SectionID;302303if (UsePreallocation)304return allocateFromSlab(Size, Alignment, true /* isCode */,305SectionName, SectionID);306307std::error_code EC;308sys::MemoryBlock MB =309sys::Memory::allocateMappedMemory(Size, nullptr,310sys::Memory::MF_READ |311sys::Memory::MF_WRITE,312EC);313if (!MB.base())314report_fatal_error(Twine("MemoryManager allocation failed: ") +315EC.message());316FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));317return (uint8_t*)MB.base();318}319320uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,321unsigned Alignment,322unsigned SectionID,323StringRef SectionName,324bool IsReadOnly) {325if (PrintAllocationRequests)326outs() << "allocateDataSection(Size = " << Size << ", Alignment = "327<< Alignment << ", SectionName = " << SectionName << ")\n";328329if (SecIDMap)330(*SecIDMap)[SectionName] = SectionID;331332if (UsePreallocation)333return allocateFromSlab(Size, Alignment, false /* isCode */, SectionName,334SectionID);335336std::error_code EC;337sys::MemoryBlock MB =338sys::Memory::allocateMappedMemory(Size, nullptr,339sys::Memory::MF_READ |340sys::Memory::MF_WRITE,341EC);342if (!MB.base())343report_fatal_error(Twine("MemoryManager allocation failed: ") +344EC.message());345DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));346return (uint8_t*)MB.base();347}348349// In case the execution needs TLS storage, we define a very small TLS memory350// area here that will be used in allocateTLSSection().351#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)352extern "C" {353alignas(16) __attribute__((visibility("hidden"), tls_model("initial-exec"),354used)) thread_local char LLVMRTDyldTLSSpace[16];355}356#endif357358TrivialMemoryManager::TLSSection359TrivialMemoryManager::allocateTLSSection(uintptr_t Size, unsigned Alignment,360unsigned SectionID,361StringRef SectionName) {362#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)363if (Size + UsedTLSStorage > sizeof(LLVMRTDyldTLSSpace)) {364return {};365}366367// Get the offset of the TLSSpace in the TLS block by using a tpoff368// relocation here.369int64_t TLSOffset;370asm("leaq LLVMRTDyldTLSSpace@tpoff, %0" : "=r"(TLSOffset));371372TLSSection Section;373// We use the storage directly as the initialization image. This means that374// when a new thread is spawned after this allocation, it will not be375// initialized correctly. This means, llvm-rtdyld will only support TLS in a376// single thread.377Section.InitializationImage =378reinterpret_cast<uint8_t *>(LLVMRTDyldTLSSpace + UsedTLSStorage);379Section.Offset = TLSOffset + UsedTLSStorage;380381UsedTLSStorage += Size;382383return Section;384#else385return {};386#endif387}388389static const char *ProgramName;390391static void ErrorAndExit(const Twine &Msg) {392errs() << ProgramName << ": error: " << Msg << "\n";393exit(1);394}395396static void loadDylibs() {397for (const std::string &Dylib : Dylibs) {398if (!sys::fs::is_regular_file(Dylib))399report_fatal_error(Twine("Dylib not found: '") + Dylib + "'.");400std::string ErrMsg;401if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))402report_fatal_error(Twine("Error loading '") + Dylib + "': " + ErrMsg);403}404}405406/* *** */407408static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {409assert(LoadObjects || !UseDebugObj);410411// Load any dylibs requested on the command line.412loadDylibs();413414// If we don't have any input files, read from stdin.415if (!InputFileList.size())416InputFileList.push_back("-");417for (auto &File : InputFileList) {418// Instantiate a dynamic linker.419TrivialMemoryManager MemMgr;420RuntimeDyld Dyld(MemMgr, MemMgr);421422// Load the input memory buffer.423424ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =425MemoryBuffer::getFileOrSTDIN(File);426if (std::error_code EC = InputBuffer.getError())427ErrorAndExit("unable to read input: '" + EC.message() + "'");428429Expected<std::unique_ptr<ObjectFile>> MaybeObj(430ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));431432if (!MaybeObj) {433std::string Buf;434raw_string_ostream OS(Buf);435logAllUnhandledErrors(MaybeObj.takeError(), OS);436OS.flush();437ErrorAndExit("unable to create object file: '" + Buf + "'");438}439440ObjectFile &Obj = **MaybeObj;441442OwningBinary<ObjectFile> DebugObj;443std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;444ObjectFile *SymbolObj = &Obj;445if (LoadObjects) {446// Load the object file447LoadedObjInfo =448Dyld.loadObject(Obj);449450if (Dyld.hasError())451ErrorAndExit(Dyld.getErrorString());452453// Resolve all the relocations we can.454Dyld.resolveRelocations();455456if (UseDebugObj) {457DebugObj = LoadedObjInfo->getObjectForDebug(Obj);458SymbolObj = DebugObj.getBinary();459LoadedObjInfo.reset();460}461}462463std::unique_ptr<DIContext> Context = DWARFContext::create(464*SymbolObj, DWARFContext::ProcessDebugRelocations::Process,465LoadedObjInfo.get());466467std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =468object::computeSymbolSizes(*SymbolObj);469470// Use symbol info to iterate functions in the object.471for (const auto &P : SymAddr) {472object::SymbolRef Sym = P.first;473Expected<SymbolRef::Type> TypeOrErr = Sym.getType();474if (!TypeOrErr) {475// TODO: Actually report errors helpfully.476consumeError(TypeOrErr.takeError());477continue;478}479SymbolRef::Type Type = *TypeOrErr;480if (Type == object::SymbolRef::ST_Function) {481Expected<StringRef> Name = Sym.getName();482if (!Name) {483// TODO: Actually report errors helpfully.484consumeError(Name.takeError());485continue;486}487Expected<uint64_t> AddrOrErr = Sym.getAddress();488if (!AddrOrErr) {489// TODO: Actually report errors helpfully.490consumeError(AddrOrErr.takeError());491continue;492}493uint64_t Addr = *AddrOrErr;494495object::SectionedAddress Address;496497uint64_t Size = P.second;498// If we're not using the debug object, compute the address of the499// symbol in memory (rather than that in the unrelocated object file)500// and use that to query the DWARFContext.501if (!UseDebugObj && LoadObjects) {502auto SecOrErr = Sym.getSection();503if (!SecOrErr) {504// TODO: Actually report errors helpfully.505consumeError(SecOrErr.takeError());506continue;507}508object::section_iterator Sec = *SecOrErr;509Address.SectionIndex = Sec->getIndex();510uint64_t SectionLoadAddress =511LoadedObjInfo->getSectionLoadAddress(*Sec);512if (SectionLoadAddress != 0)513Addr += SectionLoadAddress - Sec->getAddress();514} else if (auto SecOrErr = Sym.getSection())515Address.SectionIndex = SecOrErr.get()->getIndex();516517outs() << "Function: " << *Name << ", Size = " << Size518<< ", Addr = " << Addr << "\n";519520Address.Address = Addr;521DILineInfoTable Lines =522Context->getLineInfoForAddressRange(Address, Size);523for (auto &D : Lines) {524outs() << " Line info @ " << D.first - Addr << ": "525<< D.second.FileName << ", line:" << D.second.Line << "\n";526}527}528}529}530531return 0;532}533534static void doPreallocation(TrivialMemoryManager &MemMgr) {535// Allocate a slab of memory upfront, if required. This is used if536// we want to test small code models.537if (static_cast<intptr_t>(PreallocMemory) < 0)538report_fatal_error("Pre-allocated bytes of memory must be a positive integer.");539540// FIXME: Limit the amount of memory that can be preallocated?541if (PreallocMemory != 0)542MemMgr.preallocateSlab(PreallocMemory);543}544545static int executeInput() {546// Load any dylibs requested on the command line.547loadDylibs();548549// Instantiate a dynamic linker.550TrivialMemoryManager MemMgr;551doPreallocation(MemMgr);552RuntimeDyld Dyld(MemMgr, MemMgr);553554// If we don't have any input files, read from stdin.555if (!InputFileList.size())556InputFileList.push_back("-");557{558TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);559for (auto &File : InputFileList) {560// Load the input memory buffer.561ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =562MemoryBuffer::getFileOrSTDIN(File);563if (std::error_code EC = InputBuffer.getError())564ErrorAndExit("unable to read input: '" + EC.message() + "'");565Expected<std::unique_ptr<ObjectFile>> MaybeObj(566ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));567568if (!MaybeObj) {569std::string Buf;570raw_string_ostream OS(Buf);571logAllUnhandledErrors(MaybeObj.takeError(), OS);572OS.flush();573ErrorAndExit("unable to create object file: '" + Buf + "'");574}575576ObjectFile &Obj = **MaybeObj;577578// Load the object file579Dyld.loadObject(Obj);580if (Dyld.hasError()) {581ErrorAndExit(Dyld.getErrorString());582}583}584}585586{587TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);588// Resove all the relocations we can.589// FIXME: Error out if there are unresolved relocations.590Dyld.resolveRelocations();591}592593// Get the address of the entry point (_main by default).594void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint);595if (!MainAddress)596ErrorAndExit("no definition for '" + EntryPoint + "'");597598// Invalidate the instruction cache for each loaded function.599for (auto &FM : MemMgr.FunctionMemory) {600601auto &FM_MB = FM.MB;602603// Make sure the memory is executable.604// setExecutable will call InvalidateInstructionCache.605if (auto EC = sys::Memory::protectMappedMemory(FM_MB,606sys::Memory::MF_READ |607sys::Memory::MF_EXEC))608ErrorAndExit("unable to mark function executable: '" + EC.message() +609"'");610}611612// Dispatch to _main().613errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";614615int (*Main)(int, const char**) =616(int(*)(int,const char**)) uintptr_t(MainAddress);617std::vector<const char *> Argv;618// Use the name of the first input object module as argv[0] for the target.619Argv.push_back(InputFileList[0].data());620for (auto &Arg : InputArgv)621Argv.push_back(Arg.data());622Argv.push_back(nullptr);623int Result = 0;624{625TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);626Result = Main(Argv.size() - 1, Argv.data());627}628629return Result;630}631632static int checkAllExpressions(RuntimeDyldChecker &Checker) {633for (const auto& CheckerFileName : CheckFiles) {634ErrorOr<std::unique_ptr<MemoryBuffer>> CheckerFileBuf =635MemoryBuffer::getFileOrSTDIN(CheckerFileName);636if (std::error_code EC = CheckerFileBuf.getError())637ErrorAndExit("unable to read input '" + CheckerFileName + "': " +638EC.message());639640if (!Checker.checkAllRulesInBuffer("# rtdyld-check:",641CheckerFileBuf.get().get()))642ErrorAndExit("some checks in '" + CheckerFileName + "' failed");643}644return 0;645}646647void applySpecificSectionMappings(RuntimeDyld &Dyld,648const FileToSectionIDMap &FileToSecIDMap) {649650for (StringRef Mapping : SpecificSectionMappings) {651size_t EqualsIdx = Mapping.find_first_of('=');652std::string SectionIDStr = std::string(Mapping.substr(0, EqualsIdx));653size_t ComaIdx = Mapping.find_first_of(',');654655if (ComaIdx == StringRef::npos)656report_fatal_error("Invalid section specification '" + Mapping +657"'. Should be '<file name>,<section name>=<addr>'");658659std::string FileName = SectionIDStr.substr(0, ComaIdx);660std::string SectionName = SectionIDStr.substr(ComaIdx + 1);661unsigned SectionID =662ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));663664auto* OldAddr = Dyld.getSectionContent(SectionID).data();665std::string NewAddrStr = std::string(Mapping.substr(EqualsIdx + 1));666uint64_t NewAddr;667668if (StringRef(NewAddrStr).getAsInteger(0, NewAddr))669report_fatal_error("Invalid section address in mapping '" + Mapping +670"'.");671672Dyld.mapSectionAddress(OldAddr, NewAddr);673}674}675676// Scatter sections in all directions!677// Remaps section addresses for -verify mode. The following command line options678// can be used to customize the layout of the memory within the phony target's679// address space:680// -target-addr-start <s> -- Specify where the phony target address range starts.681// -target-addr-end <e> -- Specify where the phony target address range ends.682// -target-section-sep <d> -- Specify how big a gap should be left between the683// end of one section and the start of the next.684// Defaults to zero. Set to something big685// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.686//687static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,688RuntimeDyld &Dyld,689TrivialMemoryManager &MemMgr) {690691// Set up a work list (section addr/size pairs).692typedef std::list<const TrivialMemoryManager::SectionInfo*> WorklistT;693WorklistT Worklist;694695for (const auto& CodeSection : MemMgr.FunctionMemory)696Worklist.push_back(&CodeSection);697for (const auto& DataSection : MemMgr.DataMemory)698Worklist.push_back(&DataSection);699700// Keep an "already allocated" mapping of section target addresses to sizes.701// Sections whose address mappings aren't specified on the command line will702// allocated around the explicitly mapped sections while maintaining the703// minimum separation.704std::map<uint64_t, uint64_t> AlreadyAllocated;705706// Move the previously applied mappings (whether explicitly specified on the707// command line, or implicitly set by RuntimeDyld) into the already-allocated708// map.709for (WorklistT::iterator I = Worklist.begin(), E = Worklist.end();710I != E;) {711WorklistT::iterator Tmp = I;712++I;713714auto LoadAddr = Dyld.getSectionLoadAddress((*Tmp)->SectionID);715716if (LoadAddr != static_cast<uint64_t>(717reinterpret_cast<uintptr_t>((*Tmp)->MB.base()))) {718// A section will have a LoadAddr of 0 if it wasn't loaded for whatever719// reason (e.g. zero byte COFF sections). Don't include those sections in720// the allocation map.721if (LoadAddr != 0)722AlreadyAllocated[LoadAddr] = (*Tmp)->MB.allocatedSize();723Worklist.erase(Tmp);724}725}726727// If the -target-addr-end option wasn't explicitly passed, then set it to a728// sensible default based on the target triple.729if (TargetAddrEnd.getNumOccurrences() == 0) {730if (TargetTriple.isArch16Bit())731TargetAddrEnd = (1ULL << 16) - 1;732else if (TargetTriple.isArch32Bit())733TargetAddrEnd = (1ULL << 32) - 1;734// TargetAddrEnd already has a sensible default for 64-bit systems, so735// there's nothing to do in the 64-bit case.736}737738// Process any elements remaining in the worklist.739while (!Worklist.empty()) {740auto *CurEntry = Worklist.front();741Worklist.pop_front();742743uint64_t NextSectionAddr = TargetAddrStart;744745for (const auto &Alloc : AlreadyAllocated)746if (NextSectionAddr + CurEntry->MB.allocatedSize() + TargetSectionSep <=747Alloc.first)748break;749else750NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep;751752Dyld.mapSectionAddress(CurEntry->MB.base(), NextSectionAddr);753AlreadyAllocated[NextSectionAddr] = CurEntry->MB.allocatedSize();754}755756// Add dummy symbols to the memory manager.757for (const auto &Mapping : DummySymbolMappings) {758size_t EqualsIdx = Mapping.find_first_of('=');759760if (EqualsIdx == StringRef::npos)761report_fatal_error(Twine("Invalid dummy symbol specification '") +762Mapping + "'. Should be '<symbol name>=<addr>'");763764std::string Symbol = Mapping.substr(0, EqualsIdx);765std::string AddrStr = Mapping.substr(EqualsIdx + 1);766767uint64_t Addr;768if (StringRef(AddrStr).getAsInteger(0, Addr))769report_fatal_error(Twine("Invalid symbol mapping '") + Mapping + "'.");770771MemMgr.addDummySymbol(Symbol, Addr);772}773}774775// Load and link the objects specified on the command line, but do not execute776// anything. Instead, attach a RuntimeDyldChecker instance and call it to777// verify the correctness of the linked memory.778static int linkAndVerify() {779780// Check for missing triple.781if (TripleName == "")782ErrorAndExit("-triple required when running in -verify mode.");783784// Look up the target and build the disassembler.785Triple TheTriple(Triple::normalize(TripleName));786std::string ErrorStr;787const Target *TheTarget =788TargetRegistry::lookupTarget("", TheTriple, ErrorStr);789if (!TheTarget)790ErrorAndExit("Error accessing target '" + TripleName + "': " + ErrorStr);791792TripleName = TheTriple.getTriple();793794std::unique_ptr<MCSubtargetInfo> STI(795TheTarget->createMCSubtargetInfo(TripleName, MCPU, ""));796if (!STI)797ErrorAndExit("Unable to create subtarget info!");798799std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));800if (!MRI)801ErrorAndExit("Unable to create target register info!");802803MCTargetOptions MCOptions;804std::unique_ptr<MCAsmInfo> MAI(805TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));806if (!MAI)807ErrorAndExit("Unable to create target asm info!");808809MCContext Ctx(Triple(TripleName), MAI.get(), MRI.get(), STI.get());810811std::unique_ptr<MCDisassembler> Disassembler(812TheTarget->createMCDisassembler(*STI, Ctx));813if (!Disassembler)814ErrorAndExit("Unable to create disassembler!");815816std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());817if (!MII)818ErrorAndExit("Unable to create target instruction info!");819820std::unique_ptr<MCInstPrinter> InstPrinter(821TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));822823// Load any dylibs requested on the command line.824loadDylibs();825826// Instantiate a dynamic linker.827TrivialMemoryManager MemMgr;828doPreallocation(MemMgr);829830struct StubID {831unsigned SectionID;832uint32_t Offset;833};834using StubInfos = StringMap<StubID>;835using StubContainers = StringMap<StubInfos>;836837StubContainers StubMap;838RuntimeDyld Dyld(MemMgr, MemMgr);839Dyld.setProcessAllSections(true);840841Dyld.setNotifyStubEmitted([&StubMap](StringRef FilePath,842StringRef SectionName,843StringRef SymbolName, unsigned SectionID,844uint32_t StubOffset) {845std::string ContainerName =846(sys::path::filename(FilePath) + "/" + SectionName).str();847StubMap[ContainerName][SymbolName] = {SectionID, StubOffset};848});849850auto GetSymbolInfo =851[&Dyld, &MemMgr](852StringRef Symbol) -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {853RuntimeDyldChecker::MemoryRegionInfo SymInfo;854855// First get the target address.856if (auto InternalSymbol = Dyld.getSymbol(Symbol))857SymInfo.setTargetAddress(InternalSymbol.getAddress());858else {859// Symbol not found in RuntimeDyld. Fall back to external lookup.860#ifdef _MSC_VER861using ExpectedLookupResult =862MSVCPExpected<JITSymbolResolver::LookupResult>;863#else864using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>;865#endif866867auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>();868auto ResultF = ResultP->get_future();869870MemMgr.lookup(JITSymbolResolver::LookupSet({Symbol}),871[=](Expected<JITSymbolResolver::LookupResult> Result) {872ResultP->set_value(std::move(Result));873});874875auto Result = ResultF.get();876if (!Result)877return Result.takeError();878879auto I = Result->find(Symbol);880assert(I != Result->end() &&881"Expected symbol address if no error occurred");882SymInfo.setTargetAddress(I->second.getAddress());883}884885// Now find the symbol content if possible (otherwise leave content as a886// default-constructed StringRef).887if (auto *SymAddr = Dyld.getSymbolLocalAddress(Symbol)) {888unsigned SectionID = Dyld.getSymbolSectionID(Symbol);889if (SectionID != ~0U) {890char *CSymAddr = static_cast<char *>(SymAddr);891StringRef SecContent = Dyld.getSectionContent(SectionID);892uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data());893SymInfo.setContent(ArrayRef<char>(CSymAddr, SymSize));894SymInfo.setTargetFlags(895Dyld.getSymbol(Symbol).getFlags().getTargetFlags());896}897}898return SymInfo;899};900901auto IsSymbolValid = [&Dyld, GetSymbolInfo](StringRef Symbol) {902if (Dyld.getSymbol(Symbol))903return true;904auto SymInfo = GetSymbolInfo(Symbol);905if (!SymInfo) {906logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");907return false;908}909return SymInfo->getTargetAddress() != 0;910};911912FileToSectionIDMap FileToSecIDMap;913914auto GetSectionInfo = [&Dyld, &FileToSecIDMap](StringRef FileName,915StringRef SectionName)916-> Expected<RuntimeDyldChecker::MemoryRegionInfo> {917auto SectionID = getSectionId(FileToSecIDMap, FileName, SectionName);918if (!SectionID)919return SectionID.takeError();920RuntimeDyldChecker::MemoryRegionInfo SecInfo;921SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(*SectionID));922StringRef SecContent = Dyld.getSectionContent(*SectionID);923SecInfo.setContent(ArrayRef<char>(SecContent.data(), SecContent.size()));924return SecInfo;925};926927auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer,928StringRef SymbolName,929StringRef KindNameFilter)930-> Expected<RuntimeDyldChecker::MemoryRegionInfo> {931if (!StubMap.count(StubContainer))932return make_error<StringError>("Stub container not found: " +933StubContainer,934inconvertibleErrorCode());935if (!StubMap[StubContainer].count(SymbolName))936return make_error<StringError>("Symbol name " + SymbolName +937" in stub container " + StubContainer,938inconvertibleErrorCode());939auto &SI = StubMap[StubContainer][SymbolName];940RuntimeDyldChecker::MemoryRegionInfo StubMemInfo;941StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SI.SectionID) +942SI.Offset);943StringRef SecContent =944Dyld.getSectionContent(SI.SectionID).substr(SI.Offset);945StubMemInfo.setContent(946ArrayRef<char>(SecContent.data(), SecContent.size()));947return StubMemInfo;948};949950auto GetGOTInfo = [&GetStubInfo](StringRef StubContainer,951StringRef SymbolName) {952return GetStubInfo(StubContainer, SymbolName, "");953};954955// We will initialize this below once we have the first object file and can956// know the endianness.957std::unique_ptr<RuntimeDyldChecker> Checker;958959// If we don't have any input files, read from stdin.960if (!InputFileList.size())961InputFileList.push_back("-");962for (auto &InputFile : InputFileList) {963// Load the input memory buffer.964ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =965MemoryBuffer::getFileOrSTDIN(InputFile);966967if (std::error_code EC = InputBuffer.getError())968ErrorAndExit("unable to read input: '" + EC.message() + "'");969970Expected<std::unique_ptr<ObjectFile>> MaybeObj(971ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));972973if (!MaybeObj) {974std::string Buf;975raw_string_ostream OS(Buf);976logAllUnhandledErrors(MaybeObj.takeError(), OS);977OS.flush();978ErrorAndExit("unable to create object file: '" + Buf + "'");979}980981ObjectFile &Obj = **MaybeObj;982983if (!Checker)984Checker = std::make_unique<RuntimeDyldChecker>(985IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,986Obj.isLittleEndian() ? llvm::endianness::little987: llvm::endianness::big,988TheTriple, MCPU, SubtargetFeatures(), dbgs());989990auto FileName = sys::path::filename(InputFile);991MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);992993// Load the object file994Dyld.loadObject(Obj);995if (Dyld.hasError()) {996ErrorAndExit(Dyld.getErrorString());997}998}9991000// Re-map the section addresses into the phony target address space and add1001// dummy symbols.1002applySpecificSectionMappings(Dyld, FileToSecIDMap);1003remapSectionsAndSymbols(TheTriple, Dyld, MemMgr);10041005// Resolve all the relocations we can.1006Dyld.resolveRelocations();10071008// Register EH frames.1009Dyld.registerEHFrames();10101011int ErrorCode = checkAllExpressions(*Checker);1012if (Dyld.hasError())1013ErrorAndExit("RTDyld reported an error applying relocations:\n " +1014Dyld.getErrorString());10151016return ErrorCode;1017}10181019int main(int argc, char **argv) {1020InitLLVM X(argc, argv);1021ProgramName = argv[0];10221023llvm::InitializeAllTargetInfos();1024llvm::InitializeAllTargetMCs();1025llvm::InitializeAllDisassemblers();10261027cl::HideUnrelatedOptions({&RTDyldCategory, &getColorCategory()});1028cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");10291030ExitOnErr.setBanner(std::string(argv[0]) + ": ");10311032Timers = ShowTimes ? std::make_unique<RTDyldTimers>() : nullptr;10331034int Result = 0;1035switch (Action) {1036case AC_Execute:1037Result = executeInput();1038break;1039case AC_PrintDebugLineInfo:1040Result =1041printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ true);1042break;1043case AC_PrintLineInfo:1044Result =1045printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ false);1046break;1047case AC_PrintObjectLineInfo:1048Result =1049printLineInfoForInput(/* LoadObjects */ false, /* UseDebugObj */ false);1050break;1051case AC_Verify:1052Result = linkAndVerify();1053break;1054}1055return Result;1056}105710581059