LLVM API Documentation

Windows/Memory.inc
Go to the documentation of this file.
00001 //===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file provides the Win32 specific implementation of various Memory
00011 // management utilities
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/Support/DataTypes.h"
00016 #include "llvm/Support/ErrorHandling.h"
00017 #include "llvm/Support/Process.h"
00018 #include "llvm/Support/WindowsError.h"
00019 
00020 // The Windows.h header must be the last one included.
00021 #include "WindowsSupport.h"
00022 
00023 namespace {
00024 
00025 DWORD getWindowsProtectionFlags(unsigned Flags) {
00026   switch (Flags) {
00027   // Contrary to what you might expect, the Windows page protection flags
00028   // are not a bitwise combination of RWX values
00029   case llvm::sys::Memory::MF_READ:
00030     return PAGE_READONLY;
00031   case llvm::sys::Memory::MF_WRITE:
00032     // Note: PAGE_WRITE is not supported by VirtualProtect
00033     return PAGE_READWRITE;
00034   case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE:
00035     return PAGE_READWRITE;
00036   case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC:
00037     return PAGE_EXECUTE_READ;
00038   case llvm::sys::Memory::MF_READ |
00039          llvm::sys::Memory::MF_WRITE |
00040          llvm::sys::Memory::MF_EXEC:
00041     return PAGE_EXECUTE_READWRITE;
00042   case llvm::sys::Memory::MF_EXEC:
00043     return PAGE_EXECUTE;
00044   default:
00045     llvm_unreachable("Illegal memory protection flag specified!");
00046   }
00047   // Provide a default return value as required by some compilers.
00048   return PAGE_NOACCESS;
00049 }
00050 
00051 size_t getAllocationGranularity() {
00052   SYSTEM_INFO  Info;
00053   ::GetSystemInfo(&Info);
00054   if (Info.dwPageSize > Info.dwAllocationGranularity)
00055     return Info.dwPageSize;
00056   else
00057     return Info.dwAllocationGranularity;
00058 }
00059 
00060 } // namespace
00061 
00062 namespace llvm {
00063 namespace sys {
00064 
00065 //===----------------------------------------------------------------------===//
00066 //=== WARNING: Implementation here must contain only Win32 specific code
00067 //===          and must not be UNIX code
00068 //===----------------------------------------------------------------------===//
00069 
00070 MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
00071                                          const MemoryBlock *const NearBlock,
00072                                          unsigned Flags,
00073                                          std::error_code &EC) {
00074   EC = std::error_code();
00075   if (NumBytes == 0)
00076     return MemoryBlock();
00077 
00078   // While we'd be happy to allocate single pages, the Windows allocation
00079   // granularity may be larger than a single page (in practice, it is 64K)
00080   // so mapping less than that will create an unreachable fragment of memory.
00081   static const size_t Granularity = getAllocationGranularity();
00082   const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity;
00083 
00084   uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
00085                                 NearBlock->size()
00086                            : 0;
00087 
00088   // If the requested address is not aligned to the allocation granularity,
00089   // round up to get beyond NearBlock. VirtualAlloc would have rounded down.
00090   if (Start && Start % Granularity != 0)
00091     Start += Granularity - Start % Granularity;
00092 
00093   DWORD Protect = getWindowsProtectionFlags(Flags);
00094 
00095   void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start),
00096                             NumBlocks*Granularity,
00097                             MEM_RESERVE | MEM_COMMIT, Protect);
00098   if (PA == NULL) {
00099     if (NearBlock) {
00100       // Try again without the NearBlock hint
00101       return allocateMappedMemory(NumBytes, NULL, Flags, EC);
00102     }
00103     EC = mapWindowsError(::GetLastError());
00104     return MemoryBlock();
00105   }
00106 
00107   MemoryBlock Result;
00108   Result.Address = PA;
00109   Result.Size = NumBlocks*Granularity;
00110 
00111   if (Flags & MF_EXEC)
00112     Memory::InvalidateInstructionCache(Result.Address, Result.Size);
00113 
00114   return Result;
00115 }
00116 
00117   std::error_code Memory::releaseMappedMemory(MemoryBlock &M) {
00118   if (M.Address == 0 || M.Size == 0)
00119     return std::error_code();
00120 
00121   if (!VirtualFree(M.Address, 0, MEM_RELEASE))
00122     return mapWindowsError(::GetLastError());
00123 
00124   M.Address = 0;
00125   M.Size = 0;
00126 
00127   return std::error_code();
00128 }
00129 
00130   std::error_code Memory::protectMappedMemory(const MemoryBlock &M,
00131                                        unsigned Flags) {
00132   if (M.Address == 0 || M.Size == 0)
00133     return std::error_code();
00134 
00135   DWORD Protect = getWindowsProtectionFlags(Flags);
00136 
00137   DWORD OldFlags;
00138   if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags))
00139     return mapWindowsError(::GetLastError());
00140 
00141   if (Flags & MF_EXEC)
00142     Memory::InvalidateInstructionCache(M.Address, M.Size);
00143 
00144   return std::error_code();
00145 }
00146 
00147 /// InvalidateInstructionCache - Before the JIT can run a block of code
00148 /// that has been emitted it must invalidate the instruction cache on some
00149 /// platforms.
00150 void Memory::InvalidateInstructionCache(
00151     const void *Addr, size_t Len) {
00152   FlushInstructionCache(GetCurrentProcess(), Addr, Len);
00153 }
00154 
00155 
00156 MemoryBlock Memory::AllocateRWX(size_t NumBytes,
00157                                 const MemoryBlock *NearBlock,
00158                                 std::string *ErrMsg) {
00159   MemoryBlock MB;
00160   std::error_code EC;
00161   MB = allocateMappedMemory(NumBytes, NearBlock,
00162                             MF_READ|MF_WRITE|MF_EXEC, EC);
00163   if (EC != std::error_code() && ErrMsg) {
00164     MakeErrMsg(ErrMsg, EC.message());
00165   }
00166   return MB;
00167 }
00168 
00169 bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
00170   std::error_code EC = releaseMappedMemory(M);
00171   if (EC == std::error_code())
00172     return false;
00173   MakeErrMsg(ErrMsg, EC.message());
00174   return true;
00175 }
00176 
00177 static DWORD getProtection(const void *addr) {
00178   MEMORY_BASIC_INFORMATION info;
00179   if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
00180     return info.Protect;
00181   }
00182   return 0;
00183 }
00184 
00185 bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
00186   if (!setRangeWritable(M.Address, M.Size)) {
00187     return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
00188   }
00189   return true;
00190 }
00191 
00192 bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
00193   if (!setRangeExecutable(M.Address, M.Size)) {
00194     return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
00195   }
00196   return true;
00197 }
00198 
00199 bool Memory::setRangeWritable(const void *Addr, size_t Size) {
00200   DWORD prot = getProtection(Addr);
00201   if (!prot)
00202     return false;
00203 
00204   if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
00205     prot = PAGE_EXECUTE_READWRITE;
00206   } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
00207     prot = PAGE_READWRITE;
00208   }
00209 
00210   DWORD oldProt;
00211   Memory::InvalidateInstructionCache(Addr, Size);
00212   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
00213             == TRUE;
00214 }
00215 
00216 bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
00217   DWORD prot = getProtection(Addr);
00218   if (!prot)
00219     return false;
00220 
00221   if (prot == PAGE_NOACCESS) {
00222     prot = PAGE_EXECUTE;
00223   } else if (prot == PAGE_READONLY) {
00224     prot = PAGE_EXECUTE_READ;
00225   } else if (prot == PAGE_READWRITE) {
00226     prot = PAGE_EXECUTE_READWRITE;
00227   }
00228 
00229   DWORD oldProt;
00230   Memory::InvalidateInstructionCache(Addr, Size);
00231   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
00232             == TRUE;
00233 }
00234 
00235 } // namespace sys
00236 } // namespace llvm