29#if defined __linux__ && !defined _GNU_SOURCE
36#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
37# if __gnu_linux__ && !defined(__ANDROID__)
45# define FFI_MMAP_EXEC_WRIT 1
48# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)
52# define FFI_MMAP_EXEC_WRIT 1
56#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
61# define FFI_MMAP_EXEC_SELINUX 1
67# if FFI_EXEC_TRAMPOLINE_TABLE
71# elif FFI_MMAP_EXEC_WRIT
74#define USE_DL_PREFIX 1
76#ifndef USE_BUILTIN_FFS
77#define USE_BUILTIN_FFS 1
82#define HAVE_MORECORE 0
92#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
95#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
102#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
105#include <sys/types.h>
114#if !defined(X86_WIN32) && !defined(X86_WIN64)
118#include <sys/param.h>
124#define LACKS_SYS_MMAN_H 1
126#if FFI_MMAP_EXEC_SELINUX
127#include <sys/statfs.h>
130static int selinux_enabled = -1;
133selinux_enabled_check (
void)
140 if (statfs (
"/selinux", &sfs) >= 0
141 && (
unsigned int) sfs.f_type == 0xf97cff8cU)
143 f =
fopen (
"/proc/mounts",
"r");
154 if (
strncmp (p + 1,
"selinuxfs ", 10) == 0)
166#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
167 : (selinux_enabled = selinux_enabled_check ()))
171#define is_selinux_enabled() 0
176#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
179static int emutramp_enabled = -1;
182emutramp_enabled_check (
void)
188 f =
fopen (
"/proc/self/status",
"r");
197 if (
sscanf (
buf,
"%*s %*c%c", &emutramp) == 1)
198 ret = (emutramp ==
'E');
206#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
207 : (emutramp_enabled = emutramp_enabled_check ()))
210#elif defined (__CYGWIN__) || defined(__INTERIX)
215#define is_selinux_enabled() 0
219#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
220#define is_emutramp_enabled() 0
240#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
242static void *dlmmap(
void *,
size_t,
int,
int,
int,
off_t);
243static int dlmunmap(
void *,
size_t);
247#define munmap dlmunmap
254#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
261static int execfd = -1;
264static size_t execsize = 0;
268open_temp_exec_file_name (
char *
name,
int flags)
286open_temp_exec_file_dir (
const char *dir)
288 static const char suffix[] =
"/ffiXXXXXX";
302 fd = open (dir, flags | O_RDWR | O_EXCL | O_TMPFILE, 0700);
312 tempname = __builtin_alloca (lendir +
sizeof (suffix));
317 memcpy (tempname, dir, lendir);
318 memcpy (tempname + lendir, suffix,
sizeof (suffix));
320 return open_temp_exec_file_name (tempname, flags);
326open_temp_exec_file_env (
const char *envvar)
328 const char *value =
getenv (envvar);
333 return open_temp_exec_file_dir (value);
342open_temp_exec_file_mnt (
const char *mounts)
344 static const char *last_mounts;
345 static FILE *last_mntent;
347 if (mounts != last_mounts)
350 endmntent (last_mntent);
352 last_mounts = mounts;
355 last_mntent = setmntent (mounts,
"r");
369 if (getmntent_r (last_mntent, &mnt,
buf,
sizeof (
buf)) ==
NULL)
372 if (hasmntopt (&mnt,
"ro")
373 || hasmntopt (&mnt,
"noexec")
377 fd = open_temp_exec_file_dir (mnt.mnt_dir);
389 int (*func)(
const char *);
392} open_temp_exec_file_opts[] = {
393 { open_temp_exec_file_env,
"TMPDIR", 0 },
394 { open_temp_exec_file_dir,
"/tmp", 0 },
395 { open_temp_exec_file_dir,
"/var/tmp", 0 },
396 { open_temp_exec_file_dir,
"/dev/shm", 0 },
397 { open_temp_exec_file_env,
"HOME", 0 },
399 { open_temp_exec_file_mnt,
"/etc/mtab", 1 },
400 { open_temp_exec_file_mnt,
"/proc/mounts", 1 },
405static int open_temp_exec_file_opts_idx = 0;
411open_temp_exec_file_opts_next (
void)
413 if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
414 open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (
NULL);
416 open_temp_exec_file_opts_idx++;
417 if (open_temp_exec_file_opts_idx
418 == (
sizeof (open_temp_exec_file_opts)
419 /
sizeof (*open_temp_exec_file_opts)))
421 open_temp_exec_file_opts_idx = 0;
431open_temp_exec_file (
void)
437 fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
438 (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].
arg);
440 if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
443 if (open_temp_exec_file_opts_next ())
458dlmmap_locked (
void *start,
size_t length,
int prot,
int flags,
off_t offset)
464 open_temp_exec_file_opts_idx = 0;
466 execfd = open_temp_exec_file ();
476 flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
479 ptr = mmap (
NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
480 flags, execfd, offset);
492 && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
493 open_temp_exec_file_opts_next ();
495 start = mmap (start, length, prot, flags, execfd, offset);
499 munmap (
ptr, length);
504 mmap_exec_offset ((
char *)start, length) = (
char*)
ptr - (
char*)start;
514dlmmap (
void *start,
size_t length,
int prot,
515 int flags,
int fd,
off_t offset)
520 && prot == (PROT_READ | PROT_WRITE)
521 && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
522 && fd == -1 && offset == 0);
525 printf (
"mapping in %zi\n", length);
528 if (execfd == -1 && is_emutramp_enabled ())
530 ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
534 if (execfd == -1 && !is_selinux_enabled ())
536 ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
547 if (execsize == 0 || execfd == -1)
550 ptr = dlmmap_locked (start, length, prot, flags, offset);
556 return dlmmap_locked (start, length, prot, flags, offset);
562dlmunmap (
void *start,
size_t length)
574 printf (
"unmapping %zi\n", length);
577 if (seg && (code = add_segment_exec_offset (start, seg)) != start)
579 int ret = munmap (code, length);
584 return munmap (start, length);
587#if FFI_CLOSURE_FREE_CODE
590segment_holding_code (
mstate m,
char* addr)
594 if (addr >= add_segment_exec_offset (sp->
base, sp)
595 && addr < add_segment_exec_offset (sp->
base, sp) + sp->
size)
597 if ((sp = sp->
next) == 0)
609ffi_closure_alloc (
size_t size,
void **code)
622 *code = add_segment_exec_offset (
ptr, seg);
633ffi_closure_free (
void *
ptr)
635#if FFI_CLOSURE_FREE_CODE
639 ptr = sub_segment_exec_offset (
ptr, seg);
652#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
653#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
673ffi_closure_alloc (
size_t size,
void **code)
682ffi_closure_free (
void *
ptr)
int dlmalloc_trim(size_t)
#define dlindependent_calloc
void * dlcalloc(size_t, size_t)
void * dlmemalign(size_t, size_t)
void * dlrealloc(void *, size_t)
#define dlmalloc_footprint
size_t dlmalloc_usable_size(void *)
#define dlmalloc_max_footprint
#define dlindependent_comalloc
#define malloc_getpagesize
struct malloc_segment * next