2 * Stack-less Just-In-Time compiler
4 * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
6 * Redistribution and use in source and binary forms, with or without modification, are
7 * permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice, this list of
10 * conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 * of conditions and the following disclaimer in the documentation and/or other materials
14 * provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 This file contains a simple W^X executable memory allocator for POSIX
29 like systems and Windows
31 In *NIX, MAP_ANON is required (that is considered a feature) so make
32 sure to set the right availability macros for your system or the code
35 If your system doesn't support mapping of anonymous pages (ex: IRIX) it
36 is also likely that it doesn't need this allocator and should be using
37 the standard one instead.
39 It allocates a separate map for each code block and may waste a lot of
40 memory, because whatever was requested, will be rounded up to the page
41 size (minimum 4KB, but could be even bigger).
43 It changes the page permissions (RW <-> RX) as needed and therefore, if you
44 will be updating the code after it has been generated, need to make sure to
45 block any concurrent execution, or could result in a SIGBUS, that could
46 even manifest itself at a different address than the one that was being
49 Only use if you are unable to use the regular allocator because of security
50 restrictions and adding exceptions to your application or the system are
54 #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
55 sljit_update_wx_flags((from), (to), (enable_exec))
58 #include <sys/types.h>
62 #define SLJIT_PROT_WX PROT_MPROTECT(PROT_EXEC)
63 #define check_se_protected(ptr, size) (0)
65 #if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
67 #define SLJIT_SE_LOCK() pthread_mutex_lock(&se_lock)
68 #define SLJIT_SE_UNLOCK() pthread_mutex_unlock(&se_lock)
69 #endif /* !SLJIT_SINGLE_THREADED */
71 #define check_se_protected(ptr, size) generic_se_protected(ptr, size)
73 static SLJIT_INLINE
int generic_se_protected(void *ptr
, sljit_uw size
)
75 if (SLJIT_LIKELY(!mprotect(ptr
, size
, PROT_EXEC
)))
76 return mprotect(ptr
, size
, PROT_READ
| PROT_WRITE
);
83 #define SLJIT_SE_LOCK()
85 #ifndef SLJIT_SE_UNLOCK
86 #define SLJIT_SE_UNLOCK()
89 #define SLJIT_PROT_WX 0
92 SLJIT_API_FUNC_ATTRIBUTE
void* sljit_malloc_exec(sljit_uw size
)
94 #if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) \
95 && !defined(__NetBSD__)
96 static pthread_mutex_t se_lock
= PTHREAD_MUTEX_INITIALIZER
;
98 static int se_protected
= !SLJIT_PROT_WX
;
99 int prot
= PROT_READ
| PROT_WRITE
| SLJIT_PROT_WX
;
102 if (SLJIT_UNLIKELY(se_protected
< 0))
106 prot
|= PROT_MAX(PROT_READ
| PROT_WRITE
| PROT_EXEC
);
109 size
+= sizeof(sljit_uw
);
110 ptr
= (sljit_uw
*)mmap(NULL
, size
, prot
, MAP_PRIVATE
| MAP_ANON
, -1, 0);
112 if (ptr
== MAP_FAILED
)
115 if (SLJIT_UNLIKELY(se_protected
> 0)) {
117 se_protected
= check_se_protected(ptr
, size
);
119 if (SLJIT_UNLIKELY(se_protected
< 0)) {
120 munmap((void *)ptr
, size
);
130 #undef SLJIT_SE_UNLOCK
133 SLJIT_API_FUNC_ATTRIBUTE
void sljit_free_exec(void* ptr
)
135 sljit_uw
*start_ptr
= ((sljit_uw
*)ptr
) - 1;
136 munmap((void*)start_ptr
, *start_ptr
);
139 static void sljit_update_wx_flags(void *from
, void *to
, sljit_s32 enable_exec
)
141 sljit_uw page_mask
= (sljit_uw
)get_page_alignment();
142 sljit_uw start
= (sljit_uw
)from
;
143 sljit_uw end
= (sljit_uw
)to
;
144 int prot
= PROT_READ
| (enable_exec
? PROT_EXEC
: PROT_WRITE
);
146 SLJIT_ASSERT(start
< end
);
149 end
= (end
+ page_mask
) & ~page_mask
;
151 mprotect((void*)start
, end
- start
, prot
);
156 SLJIT_API_FUNC_ATTRIBUTE
void* sljit_malloc_exec(sljit_uw size
)
160 size
+= sizeof(sljit_uw
);
161 ptr
= (sljit_uw
*)VirtualAlloc(NULL
, size
,
162 MEM_COMMIT
| MEM_RESERVE
, PAGE_READWRITE
);
172 SLJIT_API_FUNC_ATTRIBUTE
void sljit_free_exec(void* ptr
)
174 sljit_uw start
= (sljit_uw
)ptr
- sizeof(sljit_uw
);
175 #if defined(SLJIT_DEBUG) && SLJIT_DEBUG
176 sljit_uw page_mask
= (sljit_uw
)get_page_alignment();
178 SLJIT_ASSERT(!(start
& page_mask
));
180 VirtualFree((void*)start
, 0, MEM_RELEASE
);
183 static void sljit_update_wx_flags(void *from
, void *to
, sljit_s32 enable_exec
)
186 sljit_uw page_mask
= (sljit_uw
)get_page_alignment();
187 sljit_uw start
= (sljit_uw
)from
;
188 sljit_uw end
= (sljit_uw
)to
;
189 DWORD prot
= enable_exec
? PAGE_EXECUTE
: PAGE_READWRITE
;
191 SLJIT_ASSERT(start
< end
);
194 end
= (end
+ page_mask
) & ~page_mask
;
196 VirtualProtect((void*)start
, end
- start
, prot
, &oldprot
);
199 #endif /* !windows */
201 SLJIT_API_FUNC_ATTRIBUTE
void sljit_free_unused_memory_exec(void)
203 /* This allocator does not keep unused memory for future allocations. */