Memory.inc 7.4 KB

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