/* go-trampoline.c -- allocate a trampoline for a nested function. Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include "config.h" #include #include #include #ifdef HAVE_SYS_MMAN_H #include #endif #include "go-alloc.h" #include "go-assert.h" /* In order to build a trampoline we need space which is both writable and executable. We currently just allocate a whole page. This needs to be more system dependent. */ void * __go_allocate_trampoline (size_t size, void *closure) { unsigned int page_size; void *ret; size_t off; page_size = getpagesize (); __go_assert (page_size >= size); ret = __go_alloc (2 * page_size - 1); ret = (void *) (((uintptr_t) ret + page_size - 1) & ~ ((uintptr_t) page_size - 1)); /* Because the garbage collector only looks at correct address offsets, we need to ensure that it will see the closure address. */ off = ((size + sizeof (void *) - 1) / sizeof (void *)) * sizeof (void *); __go_assert (size + off + sizeof (void *) <= page_size); __builtin_memcpy (ret + off, &closure, sizeof (void *)); #ifdef HAVE_SYS_MMAN_H { int i; i = mprotect (ret, size, PROT_READ | PROT_WRITE | PROT_EXEC); __go_assert (i == 0); } #endif return ret; }