Home | History | Annotate | Download | only in Windows
      1 //===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file provides the Win32 specific implementation of various Memory
     11 // management utilities
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm/Support/DataTypes.h"
     16 #include "llvm/Support/ErrorHandling.h"
     17 #include "llvm/Support/Process.h"
     18 #include "llvm/Support/WindowsError.h"
     19 
     20 // The Windows.h header must be the last one included.
     21 #include "WindowsSupport.h"
     22 
     23 namespace {
     24 
     25 DWORD getWindowsProtectionFlags(unsigned Flags) {
     26   switch (Flags) {
     27   // Contrary to what you might expect, the Windows page protection flags
     28   // are not a bitwise combination of RWX values
     29   case llvm::sys::Memory::MF_READ:
     30     return PAGE_READONLY;
     31   case llvm::sys::Memory::MF_WRITE:
     32     // Note: PAGE_WRITE is not supported by VirtualProtect
     33     return PAGE_READWRITE;
     34   case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE:
     35     return PAGE_READWRITE;
     36   case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC:
     37     return PAGE_EXECUTE_READ;
     38   case llvm::sys::Memory::MF_READ |
     39          llvm::sys::Memory::MF_WRITE |
     40          llvm::sys::Memory::MF_EXEC:
     41     return PAGE_EXECUTE_READWRITE;
     42   case llvm::sys::Memory::MF_EXEC:
     43     return PAGE_EXECUTE;
     44   default:
     45     llvm_unreachable("Illegal memory protection flag specified!");
     46   }
     47   // Provide a default return value as required by some compilers.
     48   return PAGE_NOACCESS;
     49 }
     50 
     51 size_t getAllocationGranularity() {
     52   SYSTEM_INFO  Info;
     53   ::GetSystemInfo(&Info);
     54   if (Info.dwPageSize > Info.dwAllocationGranularity)
     55     return Info.dwPageSize;
     56   else
     57     return Info.dwAllocationGranularity;
     58 }
     59 
     60 } // namespace
     61 
     62 namespace llvm {
     63 namespace sys {
     64 
     65 //===----------------------------------------------------------------------===//
     66 //=== WARNING: Implementation here must contain only Win32 specific code
     67 //===          and must not be UNIX code
     68 //===----------------------------------------------------------------------===//
     69 
     70 MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
     71                                          const MemoryBlock *const NearBlock,
     72                                          unsigned Flags,
     73                                          std::error_code &EC) {
     74   EC = std::error_code();
     75   if (NumBytes == 0)
     76     return MemoryBlock();
     77 
     78   // While we'd be happy to allocate single pages, the Windows allocation
     79   // granularity may be larger than a single page (in practice, it is 64K)
     80   // so mapping less than that will create an unreachable fragment of memory.
     81   // Avoid using one-time initialization of static locals here, since they
     82   // aren't thread safe with MSVC.
     83   static volatile size_t GranularityCached;
     84   size_t Granularity = GranularityCached;
     85   if (Granularity == 0) {
     86     Granularity = getAllocationGranularity();
     87     GranularityCached = Granularity;
     88   }
     89 
     90   const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity;
     91 
     92   uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
     93                                 NearBlock->size()
     94                            : 0;
     95 
     96   // If the requested address is not aligned to the allocation granularity,
     97   // round up to get beyond NearBlock. VirtualAlloc would have rounded down.
     98   if (Start && Start % Granularity != 0)
     99     Start += Granularity - Start % Granularity;
    100 
    101   DWORD Protect = getWindowsProtectionFlags(Flags);
    102 
    103   void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start),
    104                             NumBlocks*Granularity,
    105                             MEM_RESERVE | MEM_COMMIT, Protect);
    106   if (PA == NULL) {
    107     if (NearBlock) {
    108       // Try again without the NearBlock hint
    109       return allocateMappedMemory(NumBytes, NULL, Flags, EC);
    110     }
    111     EC = mapWindowsError(::GetLastError());
    112     return MemoryBlock();
    113   }
    114 
    115   MemoryBlock Result;
    116   Result.Address = PA;
    117   Result.Size = NumBlocks*Granularity;
    118 
    119   if (Flags & MF_EXEC)
    120     Memory::InvalidateInstructionCache(Result.Address, Result.Size);
    121 
    122   return Result;
    123 }
    124 
    125   std::error_code Memory::releaseMappedMemory(MemoryBlock &M) {
    126   if (M.Address == 0 || M.Size == 0)
    127     return std::error_code();
    128 
    129   if (!VirtualFree(M.Address, 0, MEM_RELEASE))
    130     return mapWindowsError(::GetLastError());
    131 
    132   M.Address = 0;
    133   M.Size = 0;
    134 
    135   return std::error_code();
    136 }
    137 
    138   std::error_code Memory::protectMappedMemory(const MemoryBlock &M,
    139                                        unsigned Flags) {
    140   if (M.Address == 0 || M.Size == 0)
    141     return std::error_code();
    142 
    143   DWORD Protect = getWindowsProtectionFlags(Flags);
    144 
    145   DWORD OldFlags;
    146   if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags))
    147     return mapWindowsError(::GetLastError());
    148 
    149   if (Flags & MF_EXEC)
    150     Memory::InvalidateInstructionCache(M.Address, M.Size);
    151 
    152   return std::error_code();
    153 }
    154 
    155 /// InvalidateInstructionCache - Before the JIT can run a block of code
    156 /// that has been emitted it must invalidate the instruction cache on some
    157 /// platforms.
    158 void Memory::InvalidateInstructionCache(
    159     const void *Addr, size_t Len) {
    160   FlushInstructionCache(GetCurrentProcess(), Addr, Len);
    161 }
    162 
    163 
    164 MemoryBlock Memory::AllocateRWX(size_t NumBytes,
    165                                 const MemoryBlock *NearBlock,
    166                                 std::string *ErrMsg) {
    167   MemoryBlock MB;
    168   std::error_code EC;
    169   MB = allocateMappedMemory(NumBytes, NearBlock,
    170                             MF_READ|MF_WRITE|MF_EXEC, EC);
    171   if (EC != std::error_code() && ErrMsg) {
    172     MakeErrMsg(ErrMsg, EC.message());
    173   }
    174   return MB;
    175 }
    176 
    177 bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
    178   std::error_code EC = releaseMappedMemory(M);
    179   if (EC == std::error_code())
    180     return false;
    181   MakeErrMsg(ErrMsg, EC.message());
    182   return true;
    183 }
    184 
    185 static DWORD getProtection(const void *addr) {
    186   MEMORY_BASIC_INFORMATION info;
    187   if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
    188     return info.Protect;
    189   }
    190   return 0;
    191 }
    192 
    193 bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
    194   if (!setRangeWritable(M.Address, M.Size)) {
    195     return MakeErrMsg(ErrMsg, "Cannot set memory to writeable");
    196   }
    197   return true;
    198 }
    199 
    200 bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
    201   if (!setRangeExecutable(M.Address, M.Size)) {
    202     return MakeErrMsg(ErrMsg, "Cannot set memory to executable");
    203   }
    204   return true;
    205 }
    206 
    207 bool Memory::setRangeWritable(const void *Addr, size_t Size) {
    208   DWORD prot = getProtection(Addr);
    209   if (!prot)
    210     return false;
    211 
    212   if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
    213     prot = PAGE_EXECUTE_READWRITE;
    214   } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
    215     prot = PAGE_READWRITE;
    216   }
    217 
    218   DWORD oldProt;
    219   Memory::InvalidateInstructionCache(Addr, Size);
    220   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
    221             == TRUE;
    222 }
    223 
    224 bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
    225   DWORD prot = getProtection(Addr);
    226   if (!prot)
    227     return false;
    228 
    229   if (prot == PAGE_NOACCESS) {
    230     prot = PAGE_EXECUTE;
    231   } else if (prot == PAGE_READONLY) {
    232     prot = PAGE_EXECUTE_READ;
    233   } else if (prot == PAGE_READWRITE) {
    234     prot = PAGE_EXECUTE_READWRITE;
    235   }
    236 
    237   DWORD oldProt;
    238   Memory::InvalidateInstructionCache(Addr, Size);
    239   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
    240             == TRUE;
    241 }
    242 
    243 } // namespace sys
    244 } // namespace llvm
    245