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
46 # define HAVE_MNTENT 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>
106 #include <sys/stat.h>
114 #if !defined(X86_WIN32) && !defined(X86_WIN64)
118 #include <sys/param.h>
123 #include <sys/mman.h>
124 #define LACKS_SYS_MMAN_H 1
126 #if FFI_MMAP_EXEC_SELINUX
127 #include <sys/statfs.h>
130 static int selinux_enabled = -1;
133 selinux_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
179 static int emutramp_enabled = -1;
182 emutramp_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)
212 #include <sys/mman.h>
215 #define is_selinux_enabled() 0
219 #ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
220 #define is_emutramp_enabled() 0
225 static void dlfree(
void*);
240 #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
242 static void *dlmmap(
void *,
size_t,
int,
int,
int,
off_t);
243 static int dlmunmap(
void *,
size_t);
247 #define munmap dlmunmap
254 #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
261 static int execfd = -1;
264 static size_t execsize = 0;
268 open_temp_exec_file_name (
char *
name,
int flags)
286 open_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);
326 open_temp_exec_file_env (
const char *envvar)
328 const char *value =
getenv (envvar);
333 return open_temp_exec_file_dir (value);
342 open_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 },
405 static int open_temp_exec_file_opts_idx = 0;
411 open_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;
431 open_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 ())
458 dlmmap_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;
514 dlmmap (
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);
562 dlmunmap (
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
590 segment_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)
609 ffi_closure_alloc (
size_t size,
void **code)
622 *code = add_segment_exec_offset (
ptr, seg);
633 ffi_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)
673 ffi_closure_alloc (
size_t size,
void **code)
682 ffi_closure_free (
void *
ptr)