blob: 646311d8cd63899a562213142128e734e27997a9 [file] [log] [blame]
Dan Gohmanf17a25c2007-07-18 16:29:46 +00001//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner081ce942007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Dan Gohmanf17a25c2007-07-18 16:29:46 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file defines some functions for various memory management utilities.
11//
12//===----------------------------------------------------------------------===//
13
14#include "Unix.h"
15#include "llvm/System/Process.h"
16
17#ifdef HAVE_SYS_MMAN_H
18#include <sys/mman.h>
19#endif
20
Evan Chengb83f6972008-09-18 07:54:21 +000021#ifdef __APPLE__
22#include <mach/mach.h>
23#endif
24
Evan Chengd23312a2008-09-16 17:28:18 +000025/// AllocateRWX - Allocate a slab of memory with read/write/execute
Dan Gohmanf17a25c2007-07-18 16:29:46 +000026/// permissions. This is typically used for JIT applications where we want
27/// to emit code to the memory then jump to it. Getting this type of memory
28/// is very OS specific.
29///
30llvm::sys::MemoryBlock
31llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock,
32 std::string *ErrMsg) {
33 if (NumBytes == 0) return MemoryBlock();
34
Evan Cheng591bfc82008-05-05 18:30:58 +000035 unsigned pageSize = Process::GetPageSize();
Dan Gohmanf17a25c2007-07-18 16:29:46 +000036 unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
37
38 int fd = -1;
39#ifdef NEED_DEV_ZERO_FOR_MMAP
40 static int zero_fd = open("/dev/zero", O_RDWR);
41 if (zero_fd == -1) {
42 MakeErrMsg(ErrMsg, "Can't open /dev/zero device");
43 return MemoryBlock();
44 }
45 fd = zero_fd;
46#endif
47
48 int flags = MAP_PRIVATE |
49#ifdef HAVE_MMAP_ANONYMOUS
50 MAP_ANONYMOUS
51#else
52 MAP_ANON
53#endif
54 ;
55
56 void* start = NearBlock ? (unsigned char*)NearBlock->base() +
57 NearBlock->size() : 0;
58
Evan Chengb83f6972008-09-18 07:54:21 +000059#if defined(__APPLE__) && defined(__arm__)
60 void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC,
61 flags, fd, 0);
62#else
Dan Gohmanf17a25c2007-07-18 16:29:46 +000063 void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC,
64 flags, fd, 0);
Evan Chengb83f6972008-09-18 07:54:21 +000065#endif
Dan Gohmanf17a25c2007-07-18 16:29:46 +000066 if (pa == MAP_FAILED) {
67 if (NearBlock) //Try again without a near hint
68 return AllocateRWX(NumBytes, 0);
69
70 MakeErrMsg(ErrMsg, "Can't allocate RWX Memory");
71 return MemoryBlock();
72 }
Evan Chengb83f6972008-09-18 07:54:21 +000073
74#if defined(__APPLE__) && defined(__arm__)
75 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa,
76 (vm_size_t)(pageSize*NumPages), 0,
77 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
78 if (KERN_SUCCESS != kr) {
Jim Grosbach724b1812008-10-03 16:17:20 +000079 MakeErrMsg(ErrMsg, "vm_protect max RX failed\n");
Evan Chengb83f6972008-09-18 07:54:21 +000080 return sys::MemoryBlock();
81 }
82
83 kr = vm_protect(mach_task_self(), (vm_address_t)pa,
84 (vm_size_t)(pageSize*NumPages), 0,
85 VM_PROT_READ | VM_PROT_WRITE);
86 if (KERN_SUCCESS != kr) {
87 MakeErrMsg(ErrMsg, "vm_protect RW failed\n");
88 return sys::MemoryBlock();
89 }
90#endif
91
Dan Gohmanf17a25c2007-07-18 16:29:46 +000092 MemoryBlock result;
93 result.Address = pa;
94 result.Size = NumPages*pageSize;
Evan Chengb83f6972008-09-18 07:54:21 +000095
Dan Gohmanf17a25c2007-07-18 16:29:46 +000096 return result;
97}
98
Dan Gohmanf17a25c2007-07-18 16:29:46 +000099bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
100 if (M.Address == 0 || M.Size == 0) return false;
101 if (0 != ::munmap(M.Address, M.Size))
102 return MakeErrMsg(ErrMsg, "Can't release RWX Memory");
103 return false;
104}
105
Jim Grosbach724b1812008-10-03 16:17:20 +0000106bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) {
107#if defined(__APPLE__) && defined(__arm__)
108 if (M.Address == 0 || M.Size == 0) return false;
109 sys::Memory::InvalidateInstructionCache(M.Address, M.Size);
110 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
111 (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE);
112 return KERN_SUCCESS == kr;
113#else
114 return true;
115#endif
116}
117
118bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) {
119#if defined(__APPLE__) && defined(__arm__)
120 if (M.Address == 0 || M.Size == 0) return false;
121 sys::Memory::InvalidateInstructionCache(M.Address, M.Size);
122 kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
123 (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
124 return KERN_SUCCESS == kr;
125#else
126 return false;
127#endif
128}
129