diff --git a/include/llvm/ExecutionEngine/JITMemoryManager.h b/include/llvm/ExecutionEngine/JITMemoryManager.h index e1f2763e1db..0d79d14d71f 100644 --- a/include/llvm/ExecutionEngine/JITMemoryManager.h +++ b/include/llvm/ExecutionEngine/JITMemoryManager.h @@ -35,6 +35,14 @@ public: /// JIT Memory Manager if the client does not provide one to the JIT. static JITMemoryManager *CreateDefaultMemManager(); + /// setMemoryWritable - When code generation is in progress, + /// the code pages may need permissions changed. + virtual void setMemoryWritable(void) = 0; + + /// setMemoryExecutable - When code generation is done and we're ready to + /// start execution, the code pages may need permissions changed. + virtual void setMemoryExecutable(void) = 0; + //===--------------------------------------------------------------------===// // Global Offset Table Management //===--------------------------------------------------------------------===// diff --git a/include/llvm/System/Memory.h b/include/llvm/System/Memory.h index 86895e2317d..4d0828b575b 100644 --- a/include/llvm/System/Memory.h +++ b/include/llvm/System/Memory.h @@ -70,10 +70,15 @@ namespace sys { /// platforms. static void InvalidateInstructionCache(const void *Addr, size_t Len); - /// SetRXPrivilege - Before the JIT can run a block of code, it has to be + /// setExecutable - Before the JIT can run a block of code, it has to be /// given read and executable privilege. Return true if it is already r-x /// or the system is able to change its previlege. - static bool SetRXPrivilege(const void *Addr, size_t Size); + static bool setExecutable (MemoryBlock &M, std::string *ErrMsg = 0); + + /// setWritable - When adding to a block of code, the JIT may need + /// to mark a block of code as RW since the protections are on page + /// boundaries, and the JIT internal allocations are not page aligned. + static bool setWritable (MemoryBlock &M, std::string *ErrMsg = 0); }; } } diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index ffaeb1c4ea9..a90a6a52fa9 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -560,6 +560,10 @@ namespace { if (ExceptionHandling) DE->setModuleInfo(Info); } + void setMemoryExecutable(void) { + MemMgr->setMemoryExecutable(); + } + private: void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub); void *getPointerToGVLazyPtr(GlobalValue *V, void *Reference, @@ -791,6 +795,8 @@ unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) { void JITEmitter::startFunction(MachineFunction &F) { uintptr_t ActualSize = 0; + // Set the memory writable, if it's not already + MemMgr->setMemoryWritable(); if (MemMgr->NeedsExactSize()) { DOUT << "ExactSize\n"; const TargetInstrInfo* TII = F.getTarget().getInstrInfo(); @@ -938,7 +944,7 @@ bool JITEmitter::finishFunction(MachineFunction &F) { Relocations.clear(); // Mark code region readable and executable if it's not so already. - sys::Memory::SetRXPrivilege(FnStart, FnEnd-FnStart); + MemMgr->setMemoryExecutable(); #ifndef NDEBUG { @@ -1086,6 +1092,10 @@ void JITEmitter::startFunctionStub(const GlobalValue* F, unsigned StubSize, void *JITEmitter::finishFunctionStub(const GlobalValue* F) { NumBytes += getCurrentPCOffset(); + + // Invalidate the icache if necessary. + sys::Memory::InvalidateInstructionCache(BufferBegin, NumBytes); + std::swap(SavedBufferBegin, BufferBegin); BufferEnd = SavedBufferEnd; CurBufferPtr = SavedCurBufferPtr; diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index 804e88df4ca..0ffc7799013 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -365,6 +365,21 @@ namespace { // Finally, remove this entry from TableBlocks. TableBlocks.erase(I); } + + /// setMemoryWritable - When code generation is in progress, + /// the code pages may need permissions changed. + void setMemoryWritable(void) + { + for (unsigned i = 0, e = Blocks.size(); i != e; ++i) + sys::Memory::setWritable(Blocks[i]); + } + /// setMemoryExecutable - When code generation is done and we're ready to + /// start execution, the code pages may need permissions changed. + void setMemoryExecutable(void) + { + for (unsigned i = 0, e = Blocks.size(); i != e; ++i) + sys::Memory::setExecutable(Blocks[i]); + } }; } diff --git a/lib/System/Memory.cpp b/lib/System/Memory.cpp index 2fc6a23a3af..3660bcb1a4a 100644 --- a/lib/System/Memory.cpp +++ b/lib/System/Memory.cpp @@ -58,14 +58,3 @@ void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, #endif // end PPC } - -bool llvm::sys::Memory::SetRXPrivilege(const void *Addr, size_t Size) { -#if defined(__APPLE__) && defined(__arm__) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, - (vm_size_t)Size, 0, - VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} diff --git a/lib/System/Unix/Memory.inc b/lib/System/Unix/Memory.inc index cf0157d5778..646311d8cd6 100644 --- a/lib/System/Unix/Memory.inc +++ b/lib/System/Unix/Memory.inc @@ -76,7 +76,7 @@ llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock, (vm_size_t)(pageSize*NumPages), 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); if (KERN_SUCCESS != kr) { - MakeErrMsg(ErrMsg, "vm_protect max RWX failed\n"); + MakeErrMsg(ErrMsg, "vm_protect max RX failed\n"); return sys::MemoryBlock(); } @@ -103,3 +103,27 @@ bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { return false; } +bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return false; +#endif +} +