1218885Sdim//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file provides the Win32 specific implementation of various Memory 11218885Sdim// management utilities 12218885Sdim// 13218885Sdim//===----------------------------------------------------------------------===// 14218885Sdim 15218885Sdim#include "llvm/Support/DataTypes.h" 16243830Sdim#include "llvm/Support/ErrorHandling.h" 17218885Sdim#include "llvm/Support/Process.h" 18249423Sdim 19249423Sdim// The Windows.h header must be the last one included. 20243830Sdim#include "Windows.h" 21218885Sdim 22243830Sdimnamespace { 23243830Sdim 24243830SdimDWORD getWindowsProtectionFlags(unsigned Flags) { 25243830Sdim switch (Flags) { 26243830Sdim // Contrary to what you might expect, the Windows page protection flags 27243830Sdim // are not a bitwise combination of RWX values 28243830Sdim case llvm::sys::Memory::MF_READ: 29243830Sdim return PAGE_READONLY; 30243830Sdim case llvm::sys::Memory::MF_WRITE: 31243830Sdim // Note: PAGE_WRITE is not supported by VirtualProtect 32243830Sdim return PAGE_READWRITE; 33243830Sdim case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: 34243830Sdim return PAGE_READWRITE; 35243830Sdim case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: 36243830Sdim return PAGE_EXECUTE_READ; 37243830Sdim case llvm::sys::Memory::MF_READ | 38243830Sdim llvm::sys::Memory::MF_WRITE | 39243830Sdim llvm::sys::Memory::MF_EXEC: 40243830Sdim return PAGE_EXECUTE_READWRITE; 41243830Sdim case llvm::sys::Memory::MF_EXEC: 42243830Sdim return PAGE_EXECUTE; 43243830Sdim default: 44243830Sdim llvm_unreachable("Illegal memory protection flag specified!"); 45243830Sdim } 46243830Sdim // Provide a default return value as required by some compilers. 47243830Sdim return PAGE_NOACCESS; 48243830Sdim} 49243830Sdim 50243830Sdimsize_t getAllocationGranularity() { 51243830Sdim SYSTEM_INFO Info; 52243830Sdim ::GetSystemInfo(&Info); 53243830Sdim if (Info.dwPageSize > Info.dwAllocationGranularity) 54243830Sdim return Info.dwPageSize; 55243830Sdim else 56243830Sdim return Info.dwAllocationGranularity; 57243830Sdim} 58243830Sdim 59243830Sdim} // namespace 60243830Sdim 61218885Sdimnamespace llvm { 62243830Sdimnamespace sys { 63218885Sdim 64218885Sdim//===----------------------------------------------------------------------===// 65218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code 66218885Sdim//=== and must not be UNIX code 67218885Sdim//===----------------------------------------------------------------------===// 68218885Sdim 69243830SdimMemoryBlock Memory::allocateMappedMemory(size_t NumBytes, 70243830Sdim const MemoryBlock *const NearBlock, 71243830Sdim unsigned Flags, 72243830Sdim error_code &EC) { 73243830Sdim EC = error_code::success(); 74243830Sdim if (NumBytes == 0) 75243830Sdim return MemoryBlock(); 76218885Sdim 77243830Sdim // While we'd be happy to allocate single pages, the Windows allocation 78243830Sdim // granularity may be larger than a single page (in practice, it is 64K) 79243830Sdim // so mapping less than that will create an unreachable fragment of memory. 80243830Sdim static const size_t Granularity = getAllocationGranularity(); 81243830Sdim const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; 82218885Sdim 83243830Sdim uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + 84243830Sdim NearBlock->size() 85263508Sdim : 0; 86218885Sdim 87243830Sdim // If the requested address is not aligned to the allocation granularity, 88243830Sdim // round up to get beyond NearBlock. VirtualAlloc would have rounded down. 89243830Sdim if (Start && Start % Granularity != 0) 90243830Sdim Start += Granularity - Start % Granularity; 91243830Sdim 92243830Sdim DWORD Protect = getWindowsProtectionFlags(Flags); 93243830Sdim 94243830Sdim void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start), 95243830Sdim NumBlocks*Granularity, 96243830Sdim MEM_RESERVE | MEM_COMMIT, Protect); 97243830Sdim if (PA == NULL) { 98226633Sdim if (NearBlock) { 99226633Sdim // Try again without the NearBlock hint 100243830Sdim return allocateMappedMemory(NumBytes, NULL, Flags, EC); 101226633Sdim } 102243830Sdim EC = error_code(::GetLastError(), system_category()); 103218885Sdim return MemoryBlock(); 104218885Sdim } 105218885Sdim 106243830Sdim MemoryBlock Result; 107243830Sdim Result.Address = PA; 108243830Sdim Result.Size = NumBlocks*Granularity; 109263508Sdim 110243830Sdim if (Flags & MF_EXEC) 111243830Sdim Memory::InvalidateInstructionCache(Result.Address, Result.Size); 112243830Sdim 113243830Sdim return Result; 114218885Sdim} 115218885Sdim 116243830Sdimerror_code Memory::releaseMappedMemory(MemoryBlock &M) { 117243830Sdim if (M.Address == 0 || M.Size == 0) 118243830Sdim return error_code::success(); 119243830Sdim 120218885Sdim if (!VirtualFree(M.Address, 0, MEM_RELEASE)) 121243830Sdim return error_code(::GetLastError(), system_category()); 122243830Sdim 123243830Sdim M.Address = 0; 124243830Sdim M.Size = 0; 125243830Sdim 126243830Sdim return error_code::success(); 127218885Sdim} 128218885Sdim 129243830Sdimerror_code Memory::protectMappedMemory(const MemoryBlock &M, 130243830Sdim unsigned Flags) { 131243830Sdim if (M.Address == 0 || M.Size == 0) 132243830Sdim return error_code::success(); 133243830Sdim 134243830Sdim DWORD Protect = getWindowsProtectionFlags(Flags); 135243830Sdim 136243830Sdim DWORD OldFlags; 137243830Sdim if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags)) 138243830Sdim return error_code(::GetLastError(), system_category()); 139243830Sdim 140243830Sdim if (Flags & MF_EXEC) 141243830Sdim Memory::InvalidateInstructionCache(M.Address, M.Size); 142243830Sdim 143243830Sdim return error_code::success(); 144243830Sdim} 145243830Sdim 146243830Sdim/// InvalidateInstructionCache - Before the JIT can run a block of code 147243830Sdim/// that has been emitted it must invalidate the instruction cache on some 148243830Sdim/// platforms. 149243830Sdimvoid Memory::InvalidateInstructionCache( 150243830Sdim const void *Addr, size_t Len) { 151243830Sdim FlushInstructionCache(GetCurrentProcess(), Addr, Len); 152243830Sdim} 153243830Sdim 154243830Sdim 155243830SdimMemoryBlock Memory::AllocateRWX(size_t NumBytes, 156243830Sdim const MemoryBlock *NearBlock, 157243830Sdim std::string *ErrMsg) { 158243830Sdim MemoryBlock MB; 159243830Sdim error_code EC; 160243830Sdim MB = allocateMappedMemory(NumBytes, NearBlock, 161243830Sdim MF_READ|MF_WRITE|MF_EXEC, EC); 162243830Sdim if (EC != error_code::success() && ErrMsg) { 163243830Sdim MakeErrMsg(ErrMsg, EC.message()); 164243830Sdim } 165243830Sdim return MB; 166243830Sdim} 167243830Sdim 168243830Sdimbool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { 169243830Sdim error_code EC = releaseMappedMemory(M); 170243830Sdim if (EC == error_code::success()) 171243830Sdim return false; 172243830Sdim MakeErrMsg(ErrMsg, EC.message()); 173243830Sdim return true; 174243830Sdim} 175243830Sdim 176226633Sdimstatic DWORD getProtection(const void *addr) { 177226633Sdim MEMORY_BASIC_INFORMATION info; 178226633Sdim if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) { 179226633Sdim return info.Protect; 180226633Sdim } 181226633Sdim return 0; 182226633Sdim} 183226633Sdim 184218885Sdimbool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { 185226633Sdim if (!setRangeWritable(M.Address, M.Size)) { 186226633Sdim return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: "); 187226633Sdim } 188218885Sdim return true; 189218885Sdim} 190218885Sdim 191218885Sdimbool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { 192226633Sdim if (!setRangeExecutable(M.Address, M.Size)) { 193226633Sdim return MakeErrMsg(ErrMsg, "Cannot set memory to executable: "); 194226633Sdim } 195226633Sdim return true; 196218885Sdim} 197218885Sdim 198218885Sdimbool Memory::setRangeWritable(const void *Addr, size_t Size) { 199226633Sdim DWORD prot = getProtection(Addr); 200226633Sdim if (!prot) 201226633Sdim return false; 202226633Sdim 203226633Sdim if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) { 204226633Sdim prot = PAGE_EXECUTE_READWRITE; 205226633Sdim } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) { 206226633Sdim prot = PAGE_READWRITE; 207226633Sdim } 208226633Sdim 209226633Sdim DWORD oldProt; 210243830Sdim Memory::InvalidateInstructionCache(Addr, Size); 211226633Sdim return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) 212226633Sdim == TRUE; 213218885Sdim} 214218885Sdim 215218885Sdimbool Memory::setRangeExecutable(const void *Addr, size_t Size) { 216226633Sdim DWORD prot = getProtection(Addr); 217226633Sdim if (!prot) 218226633Sdim return false; 219226633Sdim 220226633Sdim if (prot == PAGE_NOACCESS) { 221226633Sdim prot = PAGE_EXECUTE; 222226633Sdim } else if (prot == PAGE_READONLY) { 223226633Sdim prot = PAGE_EXECUTE_READ; 224226633Sdim } else if (prot == PAGE_READWRITE) { 225226633Sdim prot = PAGE_EXECUTE_READWRITE; 226226633Sdim } 227226633Sdim 228226633Sdim DWORD oldProt; 229243830Sdim Memory::InvalidateInstructionCache(Addr, Size); 230226633Sdim return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) 231226633Sdim == TRUE; 232218885Sdim} 233218885Sdim 234243830Sdim} // namespace sys 235243830Sdim} // namespace llvm 236