diff options
author | Andrew Kaylor <andrew.kaylor@intel.com> | 2012-09-19 20:46:12 +0000 |
---|---|---|
committer | Andrew Kaylor <andrew.kaylor@intel.com> | 2012-09-19 20:46:12 +0000 |
commit | bbf628b6cefc8d817eb9ec04c2a357ad3f27d618 (patch) | |
tree | 437492204746bba9f0f6541b72bde24aa99f3ef5 /lib/Support/Windows/Memory.inc | |
parent | 7b6f2034ac355bd3b3cc88960bf8d0e694fe3db4 (diff) | |
download | external_llvm-bbf628b6cefc8d817eb9ec04c2a357ad3f27d618.zip external_llvm-bbf628b6cefc8d817eb9ec04c2a357ad3f27d618.tar.gz external_llvm-bbf628b6cefc8d817eb9ec04c2a357ad3f27d618.tar.bz2 |
This patch adds memory support functions which will later be used to implement section-specific protection handling in MCJIT.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164249 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Support/Windows/Memory.inc')
-rw-r--r-- | lib/Support/Windows/Memory.inc | 165 |
1 files changed, 139 insertions, 26 deletions
diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc index fcc7283..cb80f28 100644 --- a/lib/Support/Windows/Memory.inc +++ b/lib/Support/Windows/Memory.inc @@ -12,51 +12,163 @@ // //===----------------------------------------------------------------------===// -#include "Windows.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" +#include "Windows.h" + +namespace { + +DWORD getWindowsProtectionFlags(unsigned Flags) { + switch (Flags) { + // Contrary to what you might expect, the Windows page protection flags + // are not a bitwise combination of RWX values + case llvm::sys::Memory::MF_READ: + return PAGE_READONLY; + case llvm::sys::Memory::MF_WRITE: + // Note: PAGE_WRITE is not supported by VirtualProtect + return PAGE_READWRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: + return PAGE_READWRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE_READ; + case llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_WRITE | + llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE_READWRITE; + case llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE; + default: + llvm_unreachable("Illegal memory protection flag specified!"); + } + // Provide a default return value as required by some compilers. + return PAGE_NOACCESS; +} + +size_t getAllocationGranularity() { + SYSTEM_INFO Info; + ::GetSystemInfo(&Info); + if (Info.dwPageSize > Info.dwAllocationGranularity) + return Info.dwPageSize; + else + return Info.dwAllocationGranularity; +} + +} // namespace namespace llvm { -using namespace sys; +namespace sys { //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code //===----------------------------------------------------------------------===// -MemoryBlock Memory::AllocateRWX(size_t NumBytes, - const MemoryBlock *NearBlock, - std::string *ErrMsg) { - if (NumBytes == 0) return MemoryBlock(); +MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, + const MemoryBlock *const NearBlock, + unsigned Flags, + error_code &EC) { + EC = error_code::success(); + if (NumBytes == 0) + return MemoryBlock(); + + // While we'd be happy to allocate single pages, the Windows allocation + // granularity may be larger than a single page (in practice, it is 64K) + // so mapping less than that will create an unreachable fragment of memory. + static const size_t Granularity = getAllocationGranularity(); + const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; - static const size_t pageSize = Process::GetPageSize(); - size_t NumPages = (NumBytes+pageSize-1)/pageSize; + uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + + NearBlock->size() + : NULL; - PVOID start = NearBlock ? static_cast<unsigned char *>(NearBlock->base()) + - NearBlock->size() : NULL; + // If the requested address is not aligned to the allocation granularity, + // round up to get beyond NearBlock. VirtualAlloc would have rounded down. + if (Start && Start % Granularity != 0) + Start += Granularity - Start % Granularity; - void *pa = VirtualAlloc(start, NumPages*pageSize, MEM_RESERVE | MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - if (pa == NULL) { + DWORD Protect = getWindowsProtectionFlags(Flags); + + void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start), + NumBlocks*Granularity, + MEM_RESERVE | MEM_COMMIT, Protect); + if (PA == NULL) { if (NearBlock) { // Try again without the NearBlock hint - return AllocateRWX(NumBytes, NULL, ErrMsg); + return allocateMappedMemory(NumBytes, NULL, Flags, EC); } - MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); + EC = error_code(::GetLastError(), system_category()); return MemoryBlock(); } - MemoryBlock result; - result.Address = pa; - result.Size = NumPages*pageSize; - return result; + MemoryBlock Result; + Result.Address = PA; + Result.Size = NumBlocks*Granularity; + ; + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(Result.Address, Result.Size); + + return Result; } -bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == 0 || M.Size == 0) return false; +error_code Memory::releaseMappedMemory(MemoryBlock &M) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + if (!VirtualFree(M.Address, 0, MEM_RELEASE)) - return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); - return false; + return error_code(::GetLastError(), system_category()); + + M.Address = 0; + M.Size = 0; + + return error_code::success(); +} + +error_code Memory::protectMappedMemory(const MemoryBlock &M, + unsigned Flags) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + + DWORD Protect = getWindowsProtectionFlags(Flags); + + DWORD OldFlags; + if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags)) + return error_code(::GetLastError(), system_category()); + + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(M.Address, M.Size); + + return error_code::success(); +} + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void Memory::InvalidateInstructionCache( + const void *Addr, size_t Len) { + FlushInstructionCache(GetCurrentProcess(), Addr, Len); +} + + +MemoryBlock Memory::AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg) { + MemoryBlock MB; + error_code EC; + MB = allocateMappedMemory(NumBytes, NearBlock, + MF_READ|MF_WRITE|MF_EXEC, EC); + if (EC != error_code::success() && ErrMsg) { + MakeErrMsg(ErrMsg, EC.message()); + } + return MB; +} + +bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + error_code EC = releaseMappedMemory(M); + if (EC == error_code::success()) + return false; + MakeErrMsg(ErrMsg, EC.message()); + return true; } static DWORD getProtection(const void *addr) { @@ -93,7 +205,7 @@ bool Memory::setRangeWritable(const void *Addr, size_t Size) { } DWORD oldProt; - sys::Memory::InvalidateInstructionCache(Addr, Size); + Memory::InvalidateInstructionCache(Addr, Size); return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) == TRUE; } @@ -112,9 +224,10 @@ bool Memory::setRangeExecutable(const void *Addr, size_t Size) { } DWORD oldProt; - sys::Memory::InvalidateInstructionCache(Addr, Size); + Memory::InvalidateInstructionCache(Addr, Size); return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) == TRUE; } -} +} // namespace sys +} // namespace llvm |