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   static const size_t Granularity = getAllocationGranularity();
     82   const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity;
     83 
     84   uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
     85                                 NearBlock->size()
     86                            : 0;
     87 
     88   // If the requested address is not aligned to the allocation granularity,
     89   // round up to get beyond NearBlock. VirtualAlloc would have rounded down.
     90   if (Start && Start % Granularity != 0)
     91     Start += Granularity - Start % Granularity;
     92 
     93   DWORD Protect = getWindowsProtectionFlags(Flags);
     94 
     95   void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start),
     96                             NumBlocks*Granularity,
     97                             MEM_RESERVE | MEM_COMMIT, Protect);
     98   if (PA == NULL) {
     99     if (NearBlock) {
    100       // Try again without the NearBlock hint
    101       return allocateMappedMemory(NumBytes, NULL, Flags, EC);
    102     }
    103     EC = mapWindowsError(::GetLastError());
    104     return MemoryBlock();
    105   }
    106 
    107   MemoryBlock Result;
    108   Result.Address = PA;
    109   Result.Size = NumBlocks*Granularity;
    110 
    111   if (Flags & MF_EXEC)
    112     Memory::InvalidateInstructionCache(Result.Address, Result.Size);
    113 
    114   return Result;
    115 }
    116 
    117   std::error_code Memory::releaseMappedMemory(MemoryBlock &M) {
    118   if (M.Address == 0 || M.Size == 0)
    119     return std::error_code();
    120 
    121   if (!VirtualFree(M.Address, 0, MEM_RELEASE))
    122     return mapWindowsError(::GetLastError());
    123 
    124   M.Address = 0;
    125   M.Size = 0;
    126 
    127   return std::error_code();
    128 }
    129 
    130   std::error_code Memory::protectMappedMemory(const MemoryBlock &M,
    131                                        unsigned Flags) {
    132   if (M.Address == 0 || M.Size == 0)
    133     return std::error_code();
    134 
    135   DWORD Protect = getWindowsProtectionFlags(Flags);
    136 
    137   DWORD OldFlags;
    138   if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags))
    139     return mapWindowsError(::GetLastError());
    140 
    141   if (Flags & MF_EXEC)
    142     Memory::InvalidateInstructionCache(M.Address, M.Size);
    143 
    144   return std::error_code();
    145 }
    146 
    147 /// InvalidateInstructionCache - Before the JIT can run a block of code
    148 /// that has been emitted it must invalidate the instruction cache on some
    149 /// platforms.
    150 void Memory::InvalidateInstructionCache(
    151     const void *Addr, size_t Len) {
    152   FlushInstructionCache(GetCurrentProcess(), Addr, Len);
    153 }
    154 
    155 
    156 MemoryBlock Memory::AllocateRWX(size_t NumBytes,
    157                                 const MemoryBlock *NearBlock,
    158                                 std::string *ErrMsg) {
    159   MemoryBlock MB;
    160   std::error_code EC;
    161   MB = allocateMappedMemory(NumBytes, NearBlock,
    162                             MF_READ|MF_WRITE|MF_EXEC, EC);
    163   if (EC != std::error_code() && ErrMsg) {
    164     MakeErrMsg(ErrMsg, EC.message());
    165   }
    166   return MB;
    167 }
    168 
    169 bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
    170   std::error_code EC = releaseMappedMemory(M);
    171   if (EC == std::error_code())
    172     return false;
    173   MakeErrMsg(ErrMsg, EC.message());
    174   return true;
    175 }
    176 
    177 static DWORD getProtection(const void *addr) {
    178   MEMORY_BASIC_INFORMATION info;
    179   if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
    180     return info.Protect;
    181   }
    182   return 0;
    183 }
    184 
    185 bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
    186   if (!setRangeWritable(M.Address, M.Size)) {
    187     return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
    188   }
    189   return true;
    190 }
    191 
    192 bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
    193   if (!setRangeExecutable(M.Address, M.Size)) {
    194     return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
    195   }
    196   return true;
    197 }
    198 
    199 bool Memory::setRangeWritable(const void *Addr, size_t Size) {
    200   DWORD prot = getProtection(Addr);
    201   if (!prot)
    202     return false;
    203 
    204   if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
    205     prot = PAGE_EXECUTE_READWRITE;
    206   } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
    207     prot = PAGE_READWRITE;
    208   }
    209 
    210   DWORD oldProt;
    211   Memory::InvalidateInstructionCache(Addr, Size);
    212   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
    213             == TRUE;
    214 }
    215 
    216 bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
    217   DWORD prot = getProtection(Addr);
    218   if (!prot)
    219     return false;
    220 
    221   if (prot == PAGE_NOACCESS) {
    222     prot = PAGE_EXECUTE;
    223   } else if (prot == PAGE_READONLY) {
    224     prot = PAGE_EXECUTE_READ;
    225   } else if (prot == PAGE_READWRITE) {
    226     prot = PAGE_EXECUTE_READWRITE;
    227   }
    228 
    229   DWORD oldProt;
    230   Memory::InvalidateInstructionCache(Addr, Size);
    231   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
    232             == TRUE;
    233 }
    234 
    235 } // namespace sys
    236 } // namespace llvm
    237