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