1 /* Jitter: mmap abstraction for executable memory allocation.
2
3 Copyright (C) 2018, 2019 Luca Saiu
4 Updated in 2020 by Luca Saiu
5 Written by Luca Saiu
6
7 This file is part of Jitter.
8
9 Jitter is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Jitter is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
21
22
23 /* Do nothing if executable memory allocation is not needed.
24 * ************************************************************************** */
25
26 /* Everything below expands to nothing where replication is disabled. This is
27 enough not to use mmap where it doesn't exist. */
28 #include <jitter/jitter.h>
29 #ifdef JITTER_REPLICATE
30
31
32
33
34 /* Include headers.
35 * ************************************************************************** */
36
37 /* Right now there are two solutions: either anonymous mmap, like in GNU and
38 other standard systems, or the ad-hoc solution in windows.
39 Include the headers we need.
40 If the host system is not in the supported set simply fail. */
41 #if defined (JITTER_HAVE_MMAP_ANONYMOUS)
42 # include <unistd.h> /* For sysconf . */
43 # include <sys/mman.h> /* For mmap and munmap . */
44 #elif defined (JITTER_HOST_OS_IS_WINDOWS)
45 # include <windows.h> /* For VirtualAlloc and VirtualFree . */
46 #else
47 # error "cannot provide a functionality equivalent to mmap"
48 #endif /* System-dependent part. */
49
50 #include <jitter/jitter-mmap.h>
51 #include <jitter/jitter-heap.h>
52
53
54
55
56 /* Executable memory allocation: primitive allocation and deallocation.
57 * ************************************************************************** */
58
59 /* The heap block size, as per jitter/jitter-heap.h . This is an OS page, as
60 used by mmap. */
61 static size_t
62 jitter_mmap_page_size;
63
64 /* The size of a block; this must still be a power of two, and a multiple of
65 jitter_mmap_page_size. */
66 static size_t
67 jitter_executable_block_size;
68
69 /* These are simple wrappers around mmap and munmap. */
70
71 /* Allocate a new buffer of the right size and return a pointer to it, or NULL.
72 This function is of type jitter_heap_primitive_allocate_function .
73
74 This allocates space for (possibly more than) an entire heap block or big
75 object. Single object allocation is be based on heap functions, and uses
76 space obtained from this function. */
77 static void *
jitter_executable_make_block_primitive(size_t size_in_bytes)78 jitter_executable_make_block_primitive (size_t size_in_bytes)
79 {
80 #if defined (JITTER_HAVE_MMAP_ANONYMOUS)
81 void *res = mmap (NULL,
82 size_in_bytes,
83 PROT_READ | PROT_WRITE | PROT_EXEC, // FIXME: check for W^E
84 MAP_PRIVATE | MAP_ANONYMOUS,
85 -1,
86 0);
87 if (res == MAP_FAILED)
88 return NULL;
89 else
90 return res;
91 #elif defined (JITTER_HOST_OS_IS_WINDOWS)
92 void *res = VirtualAlloc (NULL, size_in_bytes,
93 MEM_COMMIT | MEM_RESERVE,
94 PAGE_EXECUTE_READWRITE);
95 /* An alternative, according to what I am reading, is first using
96 VirtualAlloc to allocate readable/writable memory, then change
97 permissions with VirtualProtect. */
98 return res; /* This is NULL on failure. */
99 #else
100 # error "this should not happen"
101 #endif /* System-dependent part. */
102 }
103
104 /* Destroy the pointed buffer of the given size. This function is of type
105 jitter_heap_primitive_free_function and is used for destroying entire blocks
106 and also for unmapping the unaliged part of larger blocks. */
107 static void
jitter_executable_destroy_block_primitive(void * allocated_memory,size_t size_in_bytes)108 jitter_executable_destroy_block_primitive (void *allocated_memory,
109 size_t size_in_bytes)
110 {
111 #if defined (JITTER_HAVE_MMAP_ANONYMOUS)
112 munmap (allocated_memory, size_in_bytes);
113 #elif defined (JITTER_HOST_OS_IS_WINDOWS)
114 VirtualFree (allocated_memory, 0, MEM_RELEASE);
115 #else
116 # error "this should not happen"
117 #endif /* System-dependent part. */
118 }
119
120
121
122
123 /* Executable memory allocation: initialization and finalization.
124 * ************************************************************************** */
125
126 /* The heap for executable code, as a global. */
127 static struct jitter_heap
128 jitter_executable_heap;
129
130 void
jitter_initialize_executable(void)131 jitter_initialize_executable (void)
132 {
133 /* Find the system page size. */
134 #if defined (JITTER_HAVE_MMAP_ANONYMOUS)
135 jitter_mmap_page_size = sysconf (_SC_PAGE_SIZE);
136 #elif defined (JITTER_HOST_OS_IS_WINDOWS)
137 SYSTEM_INFO system_info;
138 GetSystemInfo (& system_info);
139 jitter_mmap_page_size = system_info.dwPageSize;
140 #else
141 # error "this should not happen"
142 #endif /* System-dependent part. */
143
144 /* Find a sensible size of a heap block. FIXME: this could be made smaller on
145 "small" machines. */
146 jitter_executable_block_size = jitter_mmap_page_size;
147 while (jitter_executable_block_size < (512 * 1024))
148 jitter_executable_block_size *= 2;
149
150 /* Initialize the global heap variable. */
151 jitter_heap_initialize (& jitter_executable_heap,
152 jitter_executable_make_block_primitive,
153 jitter_executable_destroy_block_primitive,
154 jitter_mmap_page_size,
155 #if defined (JITTER_HAVE_MMAP_ANONYMOUS)
156 jitter_executable_destroy_block_primitive,
157 #elif defined (JITTER_HOST_OS_IS_WINDOWS)
158 /* windows cannot free only part of a mapping. */
159 NULL,
160 #else
161 # error "this should not happen"
162 #endif /* System-dependent part. */
163 jitter_executable_block_size);
164 }
165
166 void
jitter_finalize_executable(void)167 jitter_finalize_executable (void)
168 {
169 /* Finalize the global heap variable. */
170 jitter_heap_finalize (& jitter_executable_heap);
171 }
172
173
174
175
176 /* Executable memory allocation: allocation and release.
177 * ************************************************************************** */
178
179 void *
jitter_executable_allocate(size_t size_in_bytes)180 jitter_executable_allocate (size_t size_in_bytes)
181 {
182 return jitter_heap_allocate (& jitter_executable_heap, size_in_bytes);
183 }
184
185 void
jitter_executable_shrink_in_place(void * object,size_t new_size_in_bytes)186 jitter_executable_shrink_in_place (void *object, size_t new_size_in_bytes)
187 {
188 jitter_heap_shrink_in_place (& jitter_executable_heap, object,
189 new_size_in_bytes);
190 }
191
192 void
jitter_executable_deallocate(void * buffer)193 jitter_executable_deallocate (void *buffer)
194 {
195 jitter_heap_free (& jitter_executable_heap, buffer);
196 }
197
198
199 /* End of the conditionally-enabled part, and end of the source file as well. */
200 #endif // #ifdef JITTER_REPLICATE
201