X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-rtdyld%2Fllvm-rtdyld.cpp;h=c5f2665a5d778e8cb82bc0bfe9ad1d8c111fb07a;hp=0d68918d5be6005c37733580a0d440b68ddaead9;hb=ea83f226acc5f3d2ea28d6162cfcb466dd72b0d0;hpb=d88454bff79d67ad786dfea850523100f110c8a8 diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 0d68918d5be..c5f2665a5d7 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -93,6 +93,11 @@ CheckFiles("check", cl::desc("File containing RuntimeDyld verifier checks."), cl::ZeroOrMore); +static cl::opt +PreallocMemory("preallocate", + cl::desc("Allocate memory upfront rather than on-demand"), + cl::init(0)); + static cl::opt TargetAddrStart("target-addr-start", cl::desc("For -verify only: start of phony target address " @@ -150,12 +155,6 @@ public: bool finalizeMemory(std::string *ErrMsg) override { return false; } - // Invalidate instruction cache for sections with execute permissions. - // Some platforms with separate data cache and instruction cache require - // explicit cache flush, otherwise JIT code manipulations (like resolved - // relocations) will get to the data cache but not to the instruction cache. - virtual void invalidateInstructionCache(); - void addDummySymbol(const std::string &Name, uint64_t Addr) { DummyExterns[Name] = Addr; } @@ -173,14 +172,48 @@ public: size_t Size) override {} void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override {} + + void preallocateSlab(uint64_t Size) { + std::string Err; + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err); + if (!MB.base()) + report_fatal_error("Can't allocate enough memory: " + Err); + + PreallocSlab = MB; + UsePreallocation = true; + SlabSize = Size; + } + + uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode) { + Size = RoundUpToAlignment(Size, Alignment); + if (CurrentSlabOffset + Size > SlabSize) + report_fatal_error("Can't allocate enough memory. Tune --preallocate"); + + uintptr_t OldSlabOffset = CurrentSlabOffset; + sys::MemoryBlock MB((void *)OldSlabOffset, Size); + if (isCode) + FunctionMemory.push_back(MB); + else + DataMemory.push_back(MB); + CurrentSlabOffset += Size; + return (uint8_t*)OldSlabOffset; + } + private: std::map DummyExterns; + sys::MemoryBlock PreallocSlab; + bool UsePreallocation = false; + uintptr_t SlabSize = 0; + uintptr_t CurrentSlabOffset = 0; }; uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) { + if (UsePreallocation) + return allocateFromSlab(Size, Alignment, true /* isCode */); + std::string Err; sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err); if (!MB.base()) @@ -194,6 +227,9 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, unsigned SectionID, StringRef SectionName, bool IsReadOnly) { + if (UsePreallocation) + return allocateFromSlab(Size, Alignment, false /* isCode */); + std::string Err; sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err); if (!MB.base()) @@ -202,22 +238,10 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, return (uint8_t*)MB.base(); } -void TrivialMemoryManager::invalidateInstructionCache() { - for (auto &FM : FunctionMemory) - sys::Memory::InvalidateInstructionCache(FM.base(), FM.size()); - - for (auto &DM : DataMemory) - sys::Memory::InvalidateInstructionCache(DM.base(), DM.size()); -} - static const char *ProgramName; -static void Message(const char *Type, const Twine &Msg) { - errs() << ProgramName << ": " << Type << ": " << Msg << "\n"; -} - static int Error(const Twine &Msg) { - Message("error", Msg); + errs() << ProgramName << ": error: " << Msg << "\n"; return 1; } @@ -332,12 +356,24 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { return 0; } +static void doPreallocation(TrivialMemoryManager &MemMgr) { + // Allocate a slab of memory upfront, if required. This is used if + // we want to test small code models. + if (static_cast(PreallocMemory) < 0) + report_fatal_error("Pre-allocated bytes of memory must be a positive integer."); + + // FIXME: Limit the amount of memory that can be preallocated? + if (PreallocMemory != 0) + MemMgr.preallocateSlab(PreallocMemory); +} + static int executeInput() { // Load any dylibs requested on the command line. loadDylibs(); // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; + doPreallocation(MemMgr); RuntimeDyld Dyld(MemMgr, MemMgr); // FIXME: Preserve buffers until resolveRelocations time to work around a bug @@ -370,12 +406,9 @@ static int executeInput() { } } - // Resolve all the relocations we can. - Dyld.resolveRelocations(); - // Clear instruction cache before code will be executed. - MemMgr.invalidateInstructionCache(); - + // Resove all the relocations we can. // FIXME: Error out if there are unresolved relocations. + Dyld.resolveRelocations(); // Get the address of the entry point (_main by default). void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint); @@ -384,9 +417,10 @@ static int executeInput() { // Invalidate the instruction cache for each loaded function. for (auto &FM : MemMgr.FunctionMemory) { + // Make sure the memory is executable. + // setExecutable will call InvalidateInstructionCache. std::string ErrorStr; - sys::Memory::InvalidateInstructionCache(FM.base(), FM.size()); if (!sys::Memory::setExecutable(FM, &ErrorStr)) return Error("unable to mark function executable: '" + ErrorStr + "'"); } @@ -429,11 +463,9 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) { std::string SectionIDStr = Mapping.substr(0, EqualsIdx); size_t ComaIdx = Mapping.find_first_of(","); - if (ComaIdx == StringRef::npos) { - errs() << "Invalid section specification '" << Mapping - << "'. Should be ',
='\n"; - exit(1); - } + if (ComaIdx == StringRef::npos) + report_fatal_error("Invalid section specification '" + Mapping + + "'. Should be ',
='"); std::string FileName = SectionIDStr.substr(0, ComaIdx); std::string SectionName = SectionIDStr.substr(ComaIdx + 1); @@ -443,20 +475,17 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) { std::tie(OldAddrInt, ErrorMsg) = Checker.getSectionAddr(FileName, SectionName, true); - if (ErrorMsg != "") { - errs() << ErrorMsg; - exit(1); - } + if (ErrorMsg != "") + report_fatal_error(ErrorMsg); void* OldAddr = reinterpret_cast(static_cast(OldAddrInt)); std::string NewAddrStr = Mapping.substr(EqualsIdx + 1); uint64_t NewAddr; - if (StringRef(NewAddrStr).getAsInteger(0, NewAddr)) { - errs() << "Invalid section address in mapping '" << Mapping << "'.\n"; - exit(1); - } + if (StringRef(NewAddrStr).getAsInteger(0, NewAddr)) + report_fatal_error("Invalid section address in mapping '" + Mapping + + "'."); Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr); SpecificMappings[OldAddr] = NewAddr; @@ -545,20 +574,16 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, for (const auto &Mapping : DummySymbolMappings) { size_t EqualsIdx = Mapping.find_first_of("="); - if (EqualsIdx == StringRef::npos) { - errs() << "Invalid dummy symbol specification '" << Mapping - << "'. Should be '='\n"; - exit(1); - } + if (EqualsIdx == StringRef::npos) + report_fatal_error("Invalid dummy symbol specification '" + Mapping + + "'. Should be '='"); std::string Symbol = Mapping.substr(0, EqualsIdx); std::string AddrStr = Mapping.substr(EqualsIdx + 1); uint64_t Addr; - if (StringRef(AddrStr).getAsInteger(0, Addr)) { - errs() << "Invalid symbol mapping '" << Mapping << "'.\n"; - exit(1); - } + if (StringRef(AddrStr).getAsInteger(0, Addr)) + report_fatal_error("Invalid symbol mapping '" + Mapping + "'."); MemMgr.addDummySymbol(Symbol, Addr); } @@ -613,6 +638,7 @@ static int linkAndVerify() { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; + doPreallocation(MemMgr); RuntimeDyld Dyld(MemMgr, MemMgr); Dyld.setProcessAllSections(true); RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),