void LLIChildTarget::handleLoadSection(bool IsCode) { // Read the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); // Read the target load address. uint64_t Addr; rc = ReadBytes(&Addr, 8); assert(rc == 8); size_t BufferSize = DataSize - 8; if (!RT->isAllocatedMemory(Addr, BufferSize)) return sendLoadStatus(LLI_Status_NotAllocated); // Read section data into previously allocated buffer rc = ReadBytes((void*)Addr, BufferSize); if (rc != (int)(BufferSize)) return sendLoadStatus(LLI_Status_IncompleteMsg); // If IsCode, mark memory executable if (IsCode) sys::Memory::InvalidateInstructionCache((void *)Addr, BufferSize); // Send MarkLoadComplete message. sendLoadStatus(LLI_Status_Success); }
void LLIChildTarget::handleExecute() { // Read the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); assert(DataSize == 8); // Read the target address. uint64_t Addr; rc = ReadBytes(&Addr, 8); assert(rc == 8); // Call function int32_t Result = -1; RT->executeCode(Addr, Result); // Send ExecutionResult message. sendExecutionComplete(Result); }
void LLIChildTarget::handleMessage(LLIMessageType messageType) { switch (messageType) { case LLI_AllocateSpace: handleAllocateSpace(); break; case LLI_LoadCodeSection: handleLoadSection(true); break; case LLI_LoadDataSection: handleLoadSection(false); break; case LLI_Execute: handleExecute(); break; case LLI_Terminate: RT->stop(); break; default: // FIXME: Handle error! break; } }
// Incoming message handlers void LLIChildTarget::handleAllocateSpace() { // Read and verify the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); assert(DataSize == 8); // Read the message arguments. uint32_t Alignment; uint32_t AllocSize; rc = ReadBytes(&Alignment, 4); assert(rc == 4); rc = ReadBytes(&AllocSize, 4); assert(rc == 4); // Allocate the memory. uint64_t Addr; RT->allocateSpace(AllocSize, Alignment, Addr); // Send AllocationResult message. sendAllocationResult(Addr); }
//===----------------------------------------------------------------------===// // main Driver function // int main(int argc, char **argv, char * const *envp) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); LLVMContext &Context = getGlobalContext(); atexit(do_shutdown); // Call llvm_shutdown() on exit. // If we have a native target, initialize it to ensure it is linked in and // usable by the JIT. InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); cl::ParseCommandLineOptions(argc, argv, "llvm interpreter & dynamic compiler\n"); // If the user doesn't want core files, disable them. if (DisableCoreFiles) sys::Process::PreventCoreFiles(); // Load the bitcode... SMDiagnostic Err; Module *Mod = ParseIRFile(InputFile, Err, Context); if (!Mod) { Err.print(argv[0], errs()); return 1; } // If not jitting lazily, load the whole bitcode file eagerly too. std::string ErrorMsg; if (NoLazyCompilation) { if (Mod->MaterializeAllPermanently(&ErrorMsg)) { errs() << argv[0] << ": bitcode didn't read correctly.\n"; errs() << "Reason: " << ErrorMsg << "\n"; exit(1); } } EngineBuilder builder(Mod); builder.setMArch(MArch); builder.setMCPU(MCPU); builder.setMAttrs(MAttrs); builder.setRelocationModel(RelocModel); builder.setCodeModel(CMModel); builder.setErrorStr(&ErrorMsg); builder.setEngineKind(ForceInterpreter ? EngineKind::Interpreter : EngineKind::JIT); // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) Mod->setTargetTriple(Triple::normalize(TargetTriple)); // Enable MCJIT if desired. JITMemoryManager *JMM = 0; if (UseMCJIT && !ForceInterpreter) { builder.setUseMCJIT(true); if (RemoteMCJIT) JMM = new RecordingMemoryManager(); else JMM = new SectionMemoryManager(); builder.setJITMemoryManager(JMM); } else { if (RemoteMCJIT) { errs() << "error: Remote process execution requires -use-mcjit\n"; exit(1); } builder.setJITMemoryManager(ForceInterpreter ? 0 : JITMemoryManager::CreateDefaultMemManager()); } CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { default: errs() << argv[0] << ": invalid optimization level.\n"; return 1; case ' ': break; case '0': OLvl = CodeGenOpt::None; break; case '1': OLvl = CodeGenOpt::Less; break; case '2': OLvl = CodeGenOpt::Default; break; case '3': OLvl = CodeGenOpt::Aggressive; break; } builder.setOptLevel(OLvl); TargetOptions Options; Options.UseSoftFloat = GenerateSoftFloatCalls; if (FloatABIForCalls != FloatABI::Default) Options.FloatABIType = FloatABIForCalls; if (GenerateSoftFloatCalls) FloatABIForCalls = FloatABI::Soft; // Remote target execution doesn't handle EH or debug registration. if (!RemoteMCJIT) { Options.JITExceptionHandling = EnableJITExceptionHandling; Options.JITEmitDebugInfo = EmitJitDebugInfo; Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk; } builder.setTargetOptions(Options); EE = builder.create(); if (!EE) { if (!ErrorMsg.empty()) errs() << argv[0] << ": error creating EE: " << ErrorMsg << "\n"; else errs() << argv[0] << ": unknown error creating EE!\n"; exit(1); } // The following functions have no effect if their respective profiling // support wasn't enabled in the build configuration. EE->RegisterJITEventListener( JITEventListener::createOProfileJITEventListener()); EE->RegisterJITEventListener( JITEventListener::createIntelJITEventListener()); if (!NoLazyCompilation && RemoteMCJIT) { errs() << "warning: remote mcjit does not support lazy compilation\n"; NoLazyCompilation = true; } EE->DisableLazyCompilation(NoLazyCompilation); // If the user specifically requested an argv[0] to pass into the program, // do it now. if (!FakeArgv0.empty()) { InputFile = FakeArgv0; } else { // Otherwise, if there is a .bc suffix on the executable strip it off, it // might confuse the program. if (StringRef(InputFile).endswith(".bc")) InputFile.erase(InputFile.length() - 3); } // Add the module's name to the start of the vector of arguments to main(). InputArgv.insert(InputArgv.begin(), InputFile); // Call the main function from M as if its signature were: // int main (int argc, char **argv, const char **envp) // using the contents of Args to determine argc & argv, and the contents of // EnvVars to determine envp. // Function *EntryFn = Mod->getFunction(EntryFunc); if (!EntryFn) { errs() << '\'' << EntryFunc << "\' function not found in module.\n"; return -1; } // If the program doesn't explicitly call exit, we will need the Exit // function later on to make an explicit call, so get the function now. Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), Type::getInt32Ty(Context), NULL); // Reset errno to zero on entry to main. errno = 0; // Remote target MCJIT doesn't (yet) support static constructors. No reason // it couldn't. This is a limitation of the LLI implemantation, not the // MCJIT itself. FIXME. // // Run static constructors. if (!RemoteMCJIT) { if (UseMCJIT && !ForceInterpreter) { // Give MCJIT a chance to apply relocations and set page permissions. EE->finalizeObject(); } EE->runStaticConstructorsDestructors(false); } if (NoLazyCompilation) { for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { Function *Fn = &*I; if (Fn != EntryFn && !Fn->isDeclaration()) EE->getPointerToFunction(Fn); } } int Result; if (RemoteMCJIT) { RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(JMM); // Everything is prepared now, so lay out our program for the target // address space, assign the section addresses to resolve any relocations, // and send it to the target. RemoteTarget Target; Target.create(); // Ask for a pointer to the entry function. This triggers the actual // compilation. (void)EE->getPointerToFunction(EntryFn); // Enough has been compiled to execute the entry function now, so // layout the target memory. layoutRemoteTargetMemory(&Target, MM); // Since we're executing in a (at least simulated) remote address space, // we can't use the ExecutionEngine::runFunctionAsMain(). We have to // grab the function address directly here and tell the remote target // to execute the function. // FIXME: argv and envp handling. uint64_t Entry = (uint64_t)EE->getPointerToFunction(EntryFn); DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at " << format("%p", Entry) << "\n"); if (Target.executeCode(Entry, Result)) errs() << "ERROR: " << Target.getErrorMsg() << "\n"; Target.stop(); } else { // Trigger compilation separately so code regions that need to be // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. if (JMM) static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache(); // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); } // Like static constructors, the remote target MCJIT support doesn't handle // this yet. It could. FIXME. if (!RemoteMCJIT) { // Run static destructors. EE->runStaticConstructorsDestructors(true); // If the program didn't call exit explicitly, we should call it now. // This ensures that any atexit handlers get called correctly. if (Function *ExitF = dyn_cast<Function>(Exit)) { std::vector<GenericValue> Args; GenericValue ResultGV; ResultGV.IntVal = APInt(32, Result); Args.push_back(ResultGV); EE->runFunction(ExitF, Args); errs() << "ERROR: exit(" << Result << ") returned!\n"; abort(); } else { errs() << "ERROR: exit defined with wrong prototype!\n"; abort(); } } return Result; }