LLVM API Documentation
00001 //===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- 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 defines some functions for various memory management utilities. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "Unix.h" 00015 #include "llvm/System/Process.h" 00016 00017 #ifdef HAVE_SYS_MMAN_H 00018 #include <sys/mman.h> 00019 #endif 00020 00021 #ifdef __APPLE__ 00022 #include <mach/mach.h> 00023 #endif 00024 00025 /// AllocateRWX - Allocate a slab of memory with read/write/execute 00026 /// permissions. This is typically used for JIT applications where we want 00027 /// to emit code to the memory then jump to it. Getting this type of memory 00028 /// is very OS specific. 00029 /// 00030 llvm::sys::MemoryBlock 00031 llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock, 00032 std::string *ErrMsg) { 00033 if (NumBytes == 0) return MemoryBlock(); 00034 00035 unsigned pageSize = Process::GetPageSize(); 00036 unsigned NumPages = (NumBytes+pageSize-1)/pageSize; 00037 00038 int fd = -1; 00039 #ifdef NEED_DEV_ZERO_FOR_MMAP 00040 static int zero_fd = open("/dev/zero", O_RDWR); 00041 if (zero_fd == -1) { 00042 MakeErrMsg(ErrMsg, "Can't open /dev/zero device"); 00043 return MemoryBlock(); 00044 } 00045 fd = zero_fd; 00046 #endif 00047 00048 int flags = MAP_PRIVATE | 00049 #ifdef HAVE_MMAP_ANONYMOUS 00050 MAP_ANONYMOUS 00051 #else 00052 MAP_ANON 00053 #endif 00054 ; 00055 00056 void* start = NearBlock ? (unsigned char*)NearBlock->base() + 00057 NearBlock->size() : 0; 00058 00059 #if defined(__APPLE__) && defined(__arm__) 00060 void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, 00061 flags, fd, 0); 00062 #else 00063 void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, 00064 flags, fd, 0); 00065 #endif 00066 if (pa == MAP_FAILED) { 00067 if (NearBlock) //Try again without a near hint 00068 return AllocateRWX(NumBytes, 0); 00069 00070 MakeErrMsg(ErrMsg, "Can't allocate RWX Memory"); 00071 return MemoryBlock(); 00072 } 00073 00074 #if defined(__APPLE__) && defined(__arm__) 00075 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa, 00076 (vm_size_t)(pageSize*NumPages), 0, 00077 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); 00078 if (KERN_SUCCESS != kr) { 00079 MakeErrMsg(ErrMsg, "vm_protect max RX failed\n"); 00080 return sys::MemoryBlock(); 00081 } 00082 00083 kr = vm_protect(mach_task_self(), (vm_address_t)pa, 00084 (vm_size_t)(pageSize*NumPages), 0, 00085 VM_PROT_READ | VM_PROT_WRITE); 00086 if (KERN_SUCCESS != kr) { 00087 MakeErrMsg(ErrMsg, "vm_protect RW failed\n"); 00088 return sys::MemoryBlock(); 00089 } 00090 #endif 00091 00092 MemoryBlock result; 00093 result.Address = pa; 00094 result.Size = NumPages*pageSize; 00095 00096 return result; 00097 } 00098 00099 bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { 00100 if (M.Address == 0 || M.Size == 0) return false; 00101 if (0 != ::munmap(M.Address, M.Size)) 00102 return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); 00103 return false; 00104 } 00105 00106 bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { 00107 #if defined(__APPLE__) && defined(__arm__) 00108 if (M.Address == 0 || M.Size == 0) return false; 00109 sys::Memory::InvalidateInstructionCache(M.Address, M.Size); 00110 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, 00111 (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); 00112 return KERN_SUCCESS == kr; 00113 #else 00114 return true; 00115 #endif 00116 } 00117 00118 bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { 00119 #if defined(__APPLE__) && defined(__arm__) 00120 if (M.Address == 0 || M.Size == 0) return false; 00121 sys::Memory::InvalidateInstructionCache(M.Address, M.Size); 00122 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, 00123 (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); 00124 return KERN_SUCCESS == kr; 00125 #else 00126 return false; 00127 #endif 00128 } 00129 00130 bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { 00131 #if defined(__APPLE__) && defined(__arm__) 00132 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, 00133 (vm_size_t)Size, 0, 00134 VM_PROT_READ | VM_PROT_WRITE); 00135 return KERN_SUCCESS == kr; 00136 #else 00137 return true; 00138 #endif 00139 } 00140 00141 bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { 00142 #if defined(__APPLE__) && defined(__arm__) 00143 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, 00144 (vm_size_t)Size, 0, 00145 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); 00146 return KERN_SUCCESS == kr; 00147 #else 00148 return true; 00149 #endif 00150 }