LLVM API Documentation

Unix/Memory.inc

Go to the documentation of this file.
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 }