re PR target/33895 (mips.c:6868: error: 'mips_output_dwarf_dtprel' defined but not...
[official-gcc.git] / libffi / src / closures.c
blobec956d04f265967f8d84292908ae8557498ab0af
1 /* -----------------------------------------------------------------------
2 closures.c - Copyright (c) 2007 Red Hat, Inc.
4 Code to allocate and deallocate memory for closures.
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
26 #if defined __linux__ && !defined _GNU_SOURCE
27 #define _GNU_SOURCE 1
28 #endif
30 #include <ffi.h>
31 #include <ffi_common.h>
33 #ifndef FFI_MMAP_EXEC_WRIT
34 # if __gnu_linux__
35 /* This macro indicates it may be forbidden to map anonymous memory
36 with both write and execute permission. Code compiled when this
37 option is defined will attempt to map such pages once, but if it
38 fails, it falls back to creating a temporary file in a writable and
39 executable filesystem and mapping pages from it into separate
40 locations in the virtual memory space, one location writable and
41 another executable. */
42 # define FFI_MMAP_EXEC_WRIT 1
43 # endif
44 #endif
46 #if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
47 # ifdef __linux__
48 /* When defined to 1 check for SELinux and if SELinux is active,
49 don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
50 might cause audit messages. */
51 # define FFI_MMAP_EXEC_SELINUX 1
52 # endif
53 #endif
55 #if FFI_CLOSURES
57 # if FFI_MMAP_EXEC_WRIT
59 #define USE_LOCKS 1
60 #define USE_DL_PREFIX 1
61 #define USE_BUILTIN_FFS 1
63 /* We need to use mmap, not sbrk. */
64 #define HAVE_MORECORE 0
66 /* We could, in theory, support mremap, but it wouldn't buy us anything. */
67 #define HAVE_MREMAP 0
69 /* We have no use for this, so save some code and data. */
70 #define NO_MALLINFO 1
72 /* We need all allocations to be in regular segments, otherwise we
73 lose track of the corresponding code address. */
74 #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
76 /* Don't allocate more than a page unless needed. */
77 #define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
79 #if FFI_CLOSURE_TEST
80 /* Don't release single pages, to avoid a worst-case scenario of
81 continuously allocating and releasing single pages, but release
82 pairs of pages, which should do just as well given that allocations
83 are likely to be small. */
84 #define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
85 #endif
87 #include <sys/types.h>
88 #include <sys/stat.h>
89 #include <fcntl.h>
90 #include <errno.h>
91 #include <unistd.h>
92 #include <string.h>
93 #include <stdio.h>
94 #include <mntent.h>
95 #include <sys/param.h>
96 #include <pthread.h>
98 /* We don't want sys/mman.h to be included after we redefine mmap and
99 dlmunmap. */
100 #include <sys/mman.h>
101 #define LACKS_SYS_MMAN_H 1
103 #if FFI_MMAP_EXEC_SELINUX
104 #include <sys/statfs.h>
105 #include <stdlib.h>
107 static int selinux_enabled = -1;
109 static int
110 selinux_enabled_check (void)
112 struct statfs sfs;
113 FILE *f;
114 char *buf = NULL;
115 size_t len = 0;
117 if (statfs ("/selinux", &sfs) >= 0
118 && (unsigned int) sfs.f_type == 0xf97cff8cU)
119 return 1;
120 f = fopen ("/proc/mounts", "r");
121 if (f == NULL)
122 return 0;
123 while (getline (&buf, &len, f) >= 0)
125 char *p = strchr (buf, ' ');
126 if (p == NULL)
127 break;
128 p = strchr (p + 1, ' ');
129 if (p == NULL)
130 break;
131 if (strncmp (p + 1, "selinuxfs ", 10) != 0)
133 free (buf);
134 fclose (f);
135 return 1;
138 free (buf);
139 fclose (f);
140 return 0;
143 #define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
144 : (selinux_enabled = selinux_enabled_check ()))
146 #else
148 #define is_selinux_enabled() 0
150 #endif
152 #define MAYBE_UNUSED __attribute__((__unused__))
154 /* Declare all functions defined in dlmalloc.c as static. */
155 static void *dlmalloc(size_t);
156 static void dlfree(void*);
157 static void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
158 static void *dlrealloc(void *, size_t) MAYBE_UNUSED;
159 static void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
160 static void *dlvalloc(size_t) MAYBE_UNUSED;
161 static int dlmallopt(int, int) MAYBE_UNUSED;
162 static size_t dlmalloc_footprint(void) MAYBE_UNUSED;
163 static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
164 static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
165 static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
166 static void *dlpvalloc(size_t) MAYBE_UNUSED;
167 static int dlmalloc_trim(size_t) MAYBE_UNUSED;
168 static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
169 static void dlmalloc_stats(void) MAYBE_UNUSED;
171 /* Use these for mmap and munmap within dlmalloc.c. */
172 static void *dlmmap(void *, size_t, int, int, int, off_t);
173 static int dlmunmap(void *, size_t);
175 #define mmap dlmmap
176 #define munmap dlmunmap
178 #include "dlmalloc.c"
180 #undef mmap
181 #undef munmap
183 /* A mutex used to synchronize access to *exec* variables in this file. */
184 static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
186 /* A file descriptor of a temporary file from which we'll map
187 executable pages. */
188 static int execfd = -1;
190 /* The amount of space already allocated from the temporary file. */
191 static size_t execsize = 0;
193 /* Open a temporary file name, and immediately unlink it. */
194 static int
195 open_temp_exec_file_name (char *name)
197 int fd = mkstemp (name);
199 if (fd != -1)
200 unlink (name);
202 return fd;
205 /* Open a temporary file in the named directory. */
206 static int
207 open_temp_exec_file_dir (const char *dir)
209 static const char suffix[] = "/ffiXXXXXX";
210 int lendir = strlen (dir);
211 char *tempname = __builtin_alloca (lendir + sizeof (suffix));
213 if (!tempname)
214 return -1;
216 memcpy (tempname, dir, lendir);
217 memcpy (tempname + lendir, suffix, sizeof (suffix));
219 return open_temp_exec_file_name (tempname);
222 /* Open a temporary file in the directory in the named environment
223 variable. */
224 static int
225 open_temp_exec_file_env (const char *envvar)
227 const char *value = getenv (envvar);
229 if (!value)
230 return -1;
232 return open_temp_exec_file_dir (value);
235 /* Open a temporary file in an executable and writable mount point
236 listed in the mounts file. Subsequent calls with the same mounts
237 keep searching for mount points in the same file. Providing NULL
238 as the mounts file closes the file. */
239 static int
240 open_temp_exec_file_mnt (const char *mounts)
242 static const char *last_mounts;
243 static FILE *last_mntent;
245 if (mounts != last_mounts)
247 if (last_mntent)
248 endmntent (last_mntent);
250 last_mounts = mounts;
252 if (mounts)
253 last_mntent = setmntent (mounts, "r");
254 else
255 last_mntent = NULL;
258 if (!last_mntent)
259 return -1;
261 for (;;)
263 int fd;
264 struct mntent mnt;
265 char buf[MAXPATHLEN * 3];
267 if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)))
268 return -1;
270 if (hasmntopt (&mnt, "ro")
271 || hasmntopt (&mnt, "noexec")
272 || access (mnt.mnt_dir, W_OK))
273 continue;
275 fd = open_temp_exec_file_dir (mnt.mnt_dir);
277 if (fd != -1)
278 return fd;
282 /* Instructions to look for a location to hold a temporary file that
283 can be mapped in for execution. */
284 static struct
286 int (*func)(const char *);
287 const char *arg;
288 int repeat;
289 } open_temp_exec_file_opts[] = {
290 { open_temp_exec_file_env, "TMPDIR", 0 },
291 { open_temp_exec_file_dir, "/tmp", 0 },
292 { open_temp_exec_file_dir, "/var/tmp", 0 },
293 { open_temp_exec_file_dir, "/dev/shm", 0 },
294 { open_temp_exec_file_env, "HOME", 0 },
295 { open_temp_exec_file_mnt, "/etc/mtab", 1 },
296 { open_temp_exec_file_mnt, "/proc/mounts", 1 },
299 /* Current index into open_temp_exec_file_opts. */
300 static int open_temp_exec_file_opts_idx = 0;
302 /* Reset a current multi-call func, then advances to the next entry.
303 If we're at the last, go back to the first and return nonzero,
304 otherwise return zero. */
305 static int
306 open_temp_exec_file_opts_next (void)
308 if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
309 open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
311 open_temp_exec_file_opts_idx++;
312 if (open_temp_exec_file_opts_idx
313 == (sizeof (open_temp_exec_file_opts)
314 / sizeof (*open_temp_exec_file_opts)))
316 open_temp_exec_file_opts_idx = 0;
317 return 1;
320 return 0;
323 /* Return a file descriptor of a temporary zero-sized file in a
324 writable and exexutable filesystem. */
325 static int
326 open_temp_exec_file (void)
328 int fd;
332 fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
333 (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
335 if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
336 || fd == -1)
338 if (open_temp_exec_file_opts_next ())
339 break;
342 while (fd == -1);
344 return fd;
347 /* Map in a chunk of memory from the temporary exec file into separate
348 locations in the virtual memory address space, one writable and one
349 executable. Returns the address of the writable portion, after
350 storing an offset to the corresponding executable portion at the
351 last word of the requested chunk. */
352 static void *
353 dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
355 void *ptr;
357 if (execfd == -1)
359 open_temp_exec_file_opts_idx = 0;
360 retry_open:
361 execfd = open_temp_exec_file ();
362 if (execfd == -1)
363 return MFAIL;
366 offset = execsize;
368 if (ftruncate (execfd, offset + length))
369 return MFAIL;
371 flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
372 flags |= MAP_SHARED;
374 ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
375 flags, execfd, offset);
376 if (ptr == MFAIL)
378 if (!offset)
380 close (execfd);
381 goto retry_open;
383 ftruncate (execfd, offset);
384 return MFAIL;
386 else if (!offset
387 && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
388 open_temp_exec_file_opts_next ();
390 start = mmap (start, length, prot, flags, execfd, offset);
392 if (start == MFAIL)
394 munmap (ptr, length);
395 ftruncate (execfd, offset);
396 return start;
399 mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
401 execsize += length;
403 return start;
406 /* Map in a writable and executable chunk of memory if possible.
407 Failing that, fall back to dlmmap_locked. */
408 static void *
409 dlmmap (void *start, size_t length, int prot,
410 int flags, int fd, off_t offset)
412 void *ptr;
414 assert (start == NULL && length % malloc_getpagesize == 0
415 && prot == (PROT_READ | PROT_WRITE)
416 && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
417 && fd == -1 && offset == 0);
419 #if FFI_CLOSURE_TEST
420 printf ("mapping in %zi\n", length);
421 #endif
423 if (execfd == -1 && !is_selinux_enabled ())
425 ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
427 if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
428 /* Cool, no need to mess with separate segments. */
429 return ptr;
431 /* If MREMAP_DUP is ever introduced and implemented, try mmap
432 with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
433 MREMAP_DUP and prot at this point. */
436 if (execsize == 0 || execfd == -1)
438 pthread_mutex_lock (&open_temp_exec_file_mutex);
439 ptr = dlmmap_locked (start, length, prot, flags, offset);
440 pthread_mutex_unlock (&open_temp_exec_file_mutex);
442 return ptr;
445 return dlmmap_locked (start, length, prot, flags, offset);
448 /* Release memory at the given address, as well as the corresponding
449 executable page if it's separate. */
450 static int
451 dlmunmap (void *start, size_t length)
453 /* We don't bother decreasing execsize or truncating the file, since
454 we can't quite tell whether we're unmapping the end of the file.
455 We don't expect frequent deallocation anyway. If we did, we
456 could locate pages in the file by writing to the pages being
457 deallocated and checking that the file contents change.
458 Yuck. */
459 msegmentptr seg = segment_holding (gm, start);
460 void *code;
462 #if FFI_CLOSURE_TEST
463 printf ("unmapping %zi\n", length);
464 #endif
466 if (seg && (code = add_segment_exec_offset (start, seg)) != start)
468 int ret = munmap (code, length);
469 if (ret)
470 return ret;
473 return munmap (start, length);
476 #if FFI_CLOSURE_FREE_CODE
477 /* Return segment holding given code address. */
478 static msegmentptr
479 segment_holding_code (mstate m, char* addr)
481 msegmentptr sp = &m->seg;
482 for (;;) {
483 if (addr >= add_segment_exec_offset (sp->base, sp)
484 && addr < add_segment_exec_offset (sp->base, sp) + sp->size)
485 return sp;
486 if ((sp = sp->next) == 0)
487 return 0;
490 #endif
492 /* Allocate a chunk of memory with the given size. Returns a pointer
493 to the writable address, and sets *CODE to the executable
494 corresponding virtual address. */
495 void *
496 ffi_closure_alloc (size_t size, void **code)
498 void *ptr;
500 if (!code)
501 return NULL;
503 ptr = dlmalloc (size);
505 if (ptr)
507 msegmentptr seg = segment_holding (gm, ptr);
509 *code = add_segment_exec_offset (ptr, seg);
512 return ptr;
515 /* Release a chunk of memory allocated with ffi_closure_alloc. If
516 FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
517 writable or the executable address given. Otherwise, only the
518 writable address can be provided here. */
519 void
520 ffi_closure_free (void *ptr)
522 #if FFI_CLOSURE_FREE_CODE
523 msegmentptr seg = segment_holding_code (gm, ptr);
525 if (seg)
526 ptr = sub_segment_exec_offset (ptr, seg);
527 #endif
529 dlfree (ptr);
533 #if FFI_CLOSURE_TEST
534 /* Do some internal sanity testing to make sure allocation and
535 deallocation of pages are working as intended. */
536 int main ()
538 void *p[3];
539 #define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
540 #define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
541 GET (0, malloc_getpagesize / 2);
542 GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
543 PUT (1);
544 GET (1, 2 * malloc_getpagesize);
545 GET (2, malloc_getpagesize / 2);
546 PUT (1);
547 PUT (0);
548 PUT (2);
549 return 0;
551 #endif /* FFI_CLOSURE_TEST */
552 # else /* ! FFI_MMAP_EXEC_WRIT */
554 /* On many systems, memory returned by malloc is writable and
555 executable, so just use it. */
557 #include <stdlib.h>
559 void *
560 ffi_closure_alloc (size_t size, void **code)
562 if (!code)
563 return NULL;
565 return *code = malloc (size);
568 void
569 ffi_closure_free (void *ptr)
571 free (ptr);
574 # endif /* ! FFI_MMAP_EXEC_WRIT */
575 #endif /* FFI_CLOSURES */