cl::desc("File containing RuntimeDyld verifier checks."),
cl::ZeroOrMore);
+static cl::opt<uint64_t>
+PreallocMemory("preallocate",
+ cl::desc("Allocate memory upfront rather than on-demand"),
+ cl::init(0));
+
static cl::opt<uint64_t>
TargetAddrStart("target-addr-start",
cl::desc("For -verify only: start of phony target address "
static cl::list<std::string>
SpecificSectionMappings("map-section",
- cl::desc("Map a section to a specific address."),
- cl::ZeroOrMore);
+ cl::desc("For -verify only: Map a section to a "
+ "specific address."),
+ cl::ZeroOrMore,
+ cl::Hidden);
+
+static cl::list<std::string>
+DummySymbolMappings("dummy-extern",
+ cl::desc("For -verify only: Inject a symbol into the extern "
+ "symbol table."),
+ cl::ZeroOrMore,
+ cl::Hidden);
+
+static cl::opt<bool>
+PrintAllocationRequests("print-alloc-requests",
+ cl::desc("Print allocation requests made to the memory "
+ "manager by RuntimeDyld"),
+ cl::Hidden);
/* *** */
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;
+ }
+
+ RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) override {
+ auto I = DummyExterns.find(Name);
+
+ if (I != DummyExterns.end())
+ return RuntimeDyld::SymbolInfo(I->second, JITSymbolFlags::Exported);
+
+ return RTDyldMemoryManager::findSymbol(Name);
+ }
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
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<std::string, uint64_t> 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) {
- sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, nullptr);
+ if (PrintAllocationRequests)
+ outs() << "allocateCodeSection(Size = " << Size << ", Alignment = "
+ << Alignment << ", SectionName = " << SectionName << ")\n";
+
+ if (UsePreallocation)
+ return allocateFromSlab(Size, Alignment, true /* isCode */);
+
+ std::string Err;
+ sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err);
+ if (!MB.base())
+ report_fatal_error("MemoryManager allocation failed: " + Err);
FunctionMemory.push_back(MB);
return (uint8_t*)MB.base();
}
unsigned SectionID,
StringRef SectionName,
bool IsReadOnly) {
- sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, nullptr);
- DataMemory.push_back(MB);
- return (uint8_t*)MB.base();
-}
+ if (PrintAllocationRequests)
+ outs() << "allocateDataSection(Size = " << Size << ", Alignment = "
+ << Alignment << ", SectionName = " << SectionName << ")\n";
-void TrivialMemoryManager::invalidateInstructionCache() {
- for (int i = 0, e = FunctionMemory.size(); i != e; ++i)
- sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(),
- FunctionMemory[i].size());
+ if (UsePreallocation)
+ return allocateFromSlab(Size, Alignment, false /* isCode */);
- for (int i = 0, e = DataMemory.size(); i != e; ++i)
- sys::Memory::InvalidateInstructionCache(DataMemory[i].base(),
- DataMemory[i].size());
+ std::string Err;
+ sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err);
+ if (!MB.base())
+ report_fatal_error("MemoryManager allocation failed: " + Err);
+ DataMemory.push_back(MB);
+ return (uint8_t*)MB.base();
}
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;
}
static void loadDylibs() {
for (const std::string &Dylib : Dylibs) {
- if (sys::fs::is_regular_file(Dylib)) {
- std::string ErrMsg;
- if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
- llvm::errs() << "Error loading '" << Dylib << "': "
- << ErrMsg << "\n";
- } else
- llvm::errs() << "Dylib not found: '" << Dylib << "'.\n";
+ if (!sys::fs::is_regular_file(Dylib))
+ report_fatal_error("Dylib not found: '" + Dylib + "'.");
+ std::string ErrMsg;
+ if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
+ report_fatal_error("Error loading '" + Dylib + "': " + ErrMsg);
}
}
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
InputFileList.push_back("-");
- for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
+ for (auto &File : InputFileList) {
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
RuntimeDyld Dyld(MemMgr, MemMgr);
// Load the input memory buffer.
ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
- MemoryBuffer::getFileOrSTDIN(InputFileList[i]);
+ MemoryBuffer::getFileOrSTDIN(File);
if (std::error_code EC = InputBuffer.getError())
return Error("unable to read input: '" + EC.message() + "'");
if (UseDebugObj) {
DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
SymbolObj = DebugObj.getBinary();
+ LoadedObjInfo.reset();
}
}
std::unique_ptr<DIContext> Context(
new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get()));
- ErrorOr<std::vector<std::pair<SymbolRef, uint64_t>>> SymAddrOrErr =
+ std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =
object::computeSymbolSizes(*SymbolObj);
- if (std::error_code EC = SymAddrOrErr.getError())
- return Error(EC.message());
// Use symbol info to iterate functions in the object.
- for (const auto &P : *SymAddrOrErr) {
+ for (const auto &P : SymAddr) {
object::SymbolRef Sym = P.first;
- object::SymbolRef::Type SymType;
- if (Sym.getType(SymType))
- continue;
- if (SymType == object::SymbolRef::ST_Function) {
- StringRef Name;
- uint64_t Addr;
- if (Sym.getName(Name))
+ if (Sym.getType() == object::SymbolRef::ST_Function) {
+ ErrorOr<StringRef> Name = Sym.getName();
+ if (!Name)
continue;
- if (Sym.getAddress(Addr))
+ ErrorOr<uint64_t> AddrOrErr = Sym.getAddress();
+ if (!AddrOrErr)
continue;
+ uint64_t Addr = *AddrOrErr;
uint64_t Size = P.second;
// If we're not using the debug object, compute the address of the
// symbol in memory (rather than that in the unrelocated object file)
// and use that to query the DWARFContext.
if (!UseDebugObj && LoadObjects) {
- object::section_iterator Sec(SymbolObj->section_end());
- Sym.getSection(Sec);
+ object::section_iterator Sec = *Sym.getSection();
StringRef SecName;
Sec->getName(SecName);
uint64_t SectionLoadAddress =
- LoadedObjInfo->getSectionLoadAddress(SecName);
+ LoadedObjInfo->getSectionLoadAddress(*Sec);
if (SectionLoadAddress != 0)
Addr += SectionLoadAddress - Sec->getAddress();
}
- outs() << "Function: " << Name << ", Size = " << Size << ", Addr = " << Addr << "\n";
+ outs() << "Function: " << *Name << ", Size = " << Size
+ << ", Addr = " << Addr << "\n";
DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
- DILineInfoTable::iterator Begin = Lines.begin();
- DILineInfoTable::iterator End = Lines.end();
- for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
- outs() << " Line info @ " << It->first - Addr << ": "
- << It->second.FileName << ", line:" << It->second.Line << "\n";
+ for (auto &D : Lines) {
+ outs() << " Line info @ " << D.first - Addr << ": "
+ << D.second.FileName << ", line:" << D.second.Line << "\n";
}
}
}
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<intptr_t>(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
- // in RuntimeDyldELF.
- // This fixme should be fixed ASAP. This is a very brittle workaround.
- std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
-
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
InputFileList.push_back("-");
- for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
+ for (auto &File : InputFileList) {
// Load the input memory buffer.
ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
- MemoryBuffer::getFileOrSTDIN(InputFileList[i]);
+ MemoryBuffer::getFileOrSTDIN(File);
if (std::error_code EC = InputBuffer.getError())
return Error("unable to read input: '" + EC.message() + "'");
ErrorOr<std::unique_ptr<ObjectFile>> MaybeObj(
return Error("unable to create object file: '" + EC.message() + "'");
ObjectFile &Obj = **MaybeObj;
- InputBuffers.push_back(std::move(*InputBuffer));
// Load the object file
Dyld.loadObject(Obj);
}
}
- // 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);
return Error("no definition for '" + EntryPoint + "'");
// Invalidate the instruction cache for each loaded function.
- for (unsigned i = 0, e = MemMgr.FunctionMemory.size(); i != e; ++i) {
- sys::MemoryBlock &Data = MemMgr.FunctionMemory[i];
+ for (auto &FM : MemMgr.FunctionMemory) {
+
// Make sure the memory is executable.
+ // setExecutable will call InvalidateInstructionCache.
std::string ErrorStr;
- sys::Memory::InvalidateInstructionCache(Data.base(), Data.size());
- if (!sys::Memory::setExecutable(Data, &ErrorStr))
+ if (!sys::Memory::setExecutable(FM, &ErrorStr))
return Error("unable to mark function executable: '" + ErrorStr + "'");
}
for (StringRef Mapping : SpecificSectionMappings) {
size_t EqualsIdx = Mapping.find_first_of("=");
- StringRef SectionIDStr = Mapping.substr(0, EqualsIdx);
+ 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 '<file name>,<section name>=<addr>'\n";
- exit(1);
- }
+ if (ComaIdx == StringRef::npos)
+ report_fatal_error("Invalid section specification '" + Mapping +
+ "'. Should be '<file name>,<section name>=<addr>'");
- StringRef FileName = SectionIDStr.substr(0, ComaIdx);
- StringRef SectionName = SectionIDStr.substr(ComaIdx + 1);
+ std::string FileName = SectionIDStr.substr(0, ComaIdx);
+ std::string SectionName = SectionIDStr.substr(ComaIdx + 1);
uint64_t OldAddrInt;
std::string ErrorMsg;
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<void*>(static_cast<uintptr_t>(OldAddrInt));
- StringRef NewAddrStr = Mapping.substr(EqualsIdx + 1);
+ std::string NewAddrStr = Mapping.substr(EqualsIdx + 1);
uint64_t NewAddr;
- if (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;
// Defaults to zero. Set to something big
// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.
//
-static void remapSections(const llvm::Triple &TargetTriple,
- const TrivialMemoryManager &MemMgr,
- RuntimeDyldChecker &Checker) {
+static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
+ TrivialMemoryManager &MemMgr,
+ RuntimeDyldChecker &Checker) {
// Set up a work list (section addr/size pairs).
typedef std::list<std::pair<void*, uint64_t>> WorklistT;
Checker.getRTDyld().mapSectionAddress(CurEntry.first, NextSectionAddr);
}
+ // Add dummy symbols to the memory manager.
+ for (const auto &Mapping : DummySymbolMappings) {
+ size_t EqualsIdx = Mapping.find_first_of("=");
+
+ if (EqualsIdx == StringRef::npos)
+ report_fatal_error("Invalid dummy symbol specification '" + Mapping +
+ "'. Should be '<symbol name>=<addr>'");
+
+ std::string Symbol = Mapping.substr(0, EqualsIdx);
+ std::string AddrStr = Mapping.substr(EqualsIdx + 1);
+
+ uint64_t Addr;
+ if (StringRef(AddrStr).getAsInteger(0, Addr))
+ report_fatal_error("Invalid symbol mapping '" + Mapping + "'.");
+
+ MemMgr.addDummySymbol(Symbol, Addr);
+ }
}
// Load and link the objects specified on the command line, but do not execute
static int linkAndVerify() {
// Check for missing triple.
- if (TripleName == "") {
- llvm::errs() << "Error: -triple required when running in -verify mode.\n";
- return 1;
- }
+ if (TripleName == "")
+ return Error("-triple required when running in -verify mode.");
// Look up the target and build the disassembler.
Triple TheTriple(Triple::normalize(TripleName));
std::string ErrorStr;
const Target *TheTarget =
TargetRegistry::lookupTarget("", TheTriple, ErrorStr);
- if (!TheTarget) {
- llvm::errs() << "Error accessing target '" << TripleName << "': "
- << ErrorStr << "\n";
- return 1;
- }
+ if (!TheTarget)
+ return Error("Error accessing target '" + TripleName + "': " + ErrorStr);
+
TripleName = TheTriple.getTriple();
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, MCPU, ""));
- assert(STI && "Unable to create subtarget info!");
+ if (!STI)
+ return Error("Unable to create subtarget info!");
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
- assert(MRI && "Unable to create target register info!");
+ if (!MRI)
+ return Error("Unable to create target register info!");
std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
- assert(MAI && "Unable to create target asm info!");
+ if (!MAI)
+ return Error("Unable to create target asm info!");
MCContext Ctx(MAI.get(), MRI.get(), nullptr);
std::unique_ptr<MCDisassembler> Disassembler(
TheTarget->createMCDisassembler(*STI, Ctx));
- assert(Disassembler && "Unable to create disassembler!");
+ if (!Disassembler)
+ return Error("Unable to create disassembler!");
std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
+ doPreallocation(MemMgr);
RuntimeDyld Dyld(MemMgr, MemMgr);
Dyld.setProcessAllSections(true);
RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
llvm::dbgs());
- // FIXME: Preserve buffers until resolveRelocations time to work around a bug
- // in RuntimeDyldELF.
- // This fixme should be fixed ASAP. This is a very brittle workaround.
- std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
-
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
InputFileList.push_back("-");
- for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
+ for (auto &Filename : InputFileList) {
// Load the input memory buffer.
ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
- MemoryBuffer::getFileOrSTDIN(InputFileList[i]);
+ MemoryBuffer::getFileOrSTDIN(Filename);
if (std::error_code EC = InputBuffer.getError())
return Error("unable to read input: '" + EC.message() + "'");
return Error("unable to create object file: '" + EC.message() + "'");
ObjectFile &Obj = **MaybeObj;
- InputBuffers.push_back(std::move(*InputBuffer));
// Load the object file
Dyld.loadObject(Obj);
}
}
- // Re-map the section addresses into the phony target address space.
- remapSections(TheTriple, MemMgr, Checker);
+ // Re-map the section addresses into the phony target address space and add
+ // dummy symbols.
+ remapSectionsAndSymbols(TheTriple, MemMgr, Checker);
// Resolve all the relocations we can.
Dyld.resolveRelocations();
Dyld.registerEHFrames();
int ErrorCode = checkAllExpressions(Checker);
- if (Dyld.hasError()) {
- errs() << "RTDyld reported an error applying relocations:\n "
- << Dyld.getErrorString() << "\n";
- ErrorCode = 1;
- }
+ if (Dyld.hasError())
+ return Error("RTDyld reported an error applying relocations:\n " +
+ Dyld.getErrorString());
return ErrorCode;
}