blob: 04684ef1059d435ef2bc021c2323261541c8ad1b [file] [log] [blame]
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Nicolas Capens1a3ce872018-10-10 10:42:36 -040015#include "ExecutableMemory.hpp"
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040016
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040017#include "Debug.hpp"
18
19#if defined(_WIN32)
20 #ifndef WIN32_LEAN_AND_MEAN
21 #define WIN32_LEAN_AND_MEAN
22 #endif
23 #include <windows.h>
24 #include <intrin.h>
25#else
26 #include <errno.h>
27 #include <sys/mman.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30#endif
31
32#include <memory.h>
33
34#undef allocate
35#undef deallocate
36
37#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined (_M_X64)) && !defined(__x86__)
38#define __x86__
39#endif
40
41namespace rr
42{
43namespace
44{
45struct Allocation
46{
47// size_t bytes;
48 unsigned char *block;
49};
50
51void *allocateRaw(size_t bytes, size_t alignment)
52{
53 ASSERT((alignment & (alignment - 1)) == 0); // Power of 2 alignment.
54
55 #if defined(LINUX_ENABLE_NAMED_MMAP)
56 void *allocation;
57 int result = posix_memalign(&allocation, alignment, bytes);
58 if(result != 0)
59 {
60 errno = result;
61 allocation = nullptr;
62 }
63 return allocation;
64 #else
65 unsigned char *block = new unsigned char[bytes + sizeof(Allocation) + alignment];
66 unsigned char *aligned = nullptr;
67
68 if(block)
69 {
70 aligned = (unsigned char*)((uintptr_t)(block + sizeof(Allocation) + alignment - 1) & -(intptr_t)alignment);
71 Allocation *allocation = (Allocation*)(aligned - sizeof(Allocation));
72
73 // allocation->bytes = bytes;
74 allocation->block = block;
75 }
76
77 return aligned;
78 #endif
79}
80
81#if defined(LINUX_ENABLE_NAMED_MMAP)
82// Create a file descriptor for anonymous memory with the given
83// name. Returns -1 on failure.
84// TODO: remove once libc wrapper exists.
85int memfd_create(const char* name, unsigned int flags)
86{
87 #if __aarch64__
88 #define __NR_memfd_create 279
89 #elif __arm__
90 #define __NR_memfd_create 279
91 #elif __powerpc64__
92 #define __NR_memfd_create 360
93 #elif __i386__
94 #define __NR_memfd_create 356
95 #elif __x86_64__
96 #define __NR_memfd_create 319
97 #endif /* __NR_memfd_create__ */
98 #ifdef __NR_memfd_create
99 // In the event of no system call this returns -1 with errno set
100 // as ENOSYS.
101 return syscall(__NR_memfd_create, name, flags);
102 #else
103 return -1;
104 #endif
105}
106
107// Returns a file descriptor for use with an anonymous mmap, if
108// memfd_create fails, -1 is returned. Note, the mappings should be
109// MAP_PRIVATE so that underlying pages aren't shared.
110int anonymousFd()
111{
112 static int fd = memfd_create("SwiftShader JIT", 0);
113 return fd;
114}
115
116// Ensure there is enough space in the "anonymous" fd for length.
117void ensureAnonFileSize(int anonFd, size_t length)
118{
119 static size_t fileSize = 0;
120 if(length > fileSize)
121 {
122 ftruncate(anonFd, length);
123 fileSize = length;
124 }
125}
126#endif // defined(LINUX_ENABLE_NAMED_MMAP)
127
128} // anonymous namespace
129
130size_t memoryPageSize()
131{
132 static int pageSize = 0;
133
134 if(pageSize == 0)
135 {
136 #if defined(_WIN32)
137 SYSTEM_INFO systemInfo;
138 GetSystemInfo(&systemInfo);
139 pageSize = systemInfo.dwPageSize;
140 #else
141 pageSize = sysconf(_SC_PAGESIZE);
142 #endif
143 }
144
145 return pageSize;
146}
147
148void *allocate(size_t bytes, size_t alignment)
149{
150 void *memory = allocateRaw(bytes, alignment);
151
152 if(memory)
153 {
154 memset(memory, 0, bytes);
155 }
156
157 return memory;
158}
159
160void deallocate(void *memory)
161{
162 #if defined(LINUX_ENABLE_NAMED_MMAP)
163 free(memory);
164 #else
165 if(memory)
166 {
167 unsigned char *aligned = (unsigned char*)memory;
168 Allocation *allocation = (Allocation*)(aligned - sizeof(Allocation));
169
170 delete[] allocation->block;
171 }
172 #endif
173}
174
175void *allocateExecutable(size_t bytes)
176{
177 size_t pageSize = memoryPageSize();
178 size_t length = (bytes + pageSize - 1) & ~(pageSize - 1);
179 void *mapping;
180
181 #if defined(LINUX_ENABLE_NAMED_MMAP)
182 // Try to name the memory region for the executable code,
183 // to aid profilers.
184 int anonFd = anonymousFd();
185 if(anonFd == -1)
186 {
187 mapping = mmap(nullptr, length, PROT_READ | PROT_WRITE,
188 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
189 }
190 else
191 {
192 ensureAnonFileSize(anonFd, length);
193 mapping = mmap(nullptr, length, PROT_READ | PROT_WRITE,
194 MAP_PRIVATE, anonFd, 0);
195 }
196
197 if(mapping == MAP_FAILED)
198 {
199 mapping = nullptr;
200 }
201 #else
202 mapping = allocate(length, pageSize);
203 #endif
204
205 return mapping;
206}
207
208void markExecutable(void *memory, size_t bytes)
209{
210 #if defined(_WIN32)
211 unsigned long oldProtection;
212 VirtualProtect(memory, bytes, PAGE_EXECUTE_READ, &oldProtection);
213 #else
214 mprotect(memory, bytes, PROT_READ | PROT_EXEC);
215 #endif
216}
217
218void deallocateExecutable(void *memory, size_t bytes)
219{
220 #if defined(_WIN32)
221 unsigned long oldProtection;
222 VirtualProtect(memory, bytes, PAGE_READWRITE, &oldProtection);
223 deallocate(memory);
224 #elif defined(LINUX_ENABLE_NAMED_MMAP)
225 size_t pageSize = memoryPageSize();
226 size_t length = (bytes + pageSize - 1) & ~(pageSize - 1);
227 munmap(memory, length);
228 #else
229 mprotect(memory, bytes, PROT_READ | PROT_WRITE);
230 deallocate(memory);
231 #endif
232}
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400233}