Add support for allocating nested function trampolines on an
executable heap rather than on the stack. This is motivated by targets
such as AArch64 Darwin, which globally prohibit executing code on the
stack.
The target-specific routines for allocating and writing trampolines is
to be provided in libgcc, and is by-default _not_ compiled in unless
the target specifically requires it, or you manually provide
--enable-off-stack-trampolines when configuring gcc/libgcc.
The gcc flag -foff-stack-trampolines controls whether to generate code
that instantiates trampolines on the stack, or to emit calls to
__builtin_nested_func_ptr_created and
__builtin_nested_func_ptr_deleted. Note that this flag is completely
independent of libgcc: If libgcc is for any reason missing those
symbols, you will get a link failure.
This implementation imposes some implicit restrictions as compared to
stack trampolines. longjmp'ing back to a state before a trampoline was
created will cause us to skip over the corresponding
__builtin_nested_func_ptr_deleted, which will leak trampolines
starting from the beginning of the linked list of allocated
trampolines. There may be scope for instrumenting longjmp/setjmp to
trigger cleanups of trampolines.
Co-authored-by: Andrew Burgess
gcc/ChangeLog:
* builtins.def (BUILT_IN_NESTED_PTR_CREATED): Define.
(BUILT_IN_NESTED_PTR_DELETED): Ditto.
* common.opt (foff-stack-trampolines): Add flag to control
generation of heap-based trampoline instantiation.
* tree-nested.c (convert_tramp_reference_op): Don't bother calling
__builtin_adjust_trampoline for the off-stack case.
(finalize_nesting_tree_1): Emit calls to
__builtin_nested_...{created,deleted} if we're generating with
-foff-stack-trampolines.
* tree.c (build_common_builtin_nodes): Build
__builtin_nested_...{created,deleted}.
* dov/invoke.texi (-foff-stack-trampolines): Document.
libgcc/ChangeLog:
* configure.ac: Add configure parameter
--enable-off-stack-trampolines, and do error checking if we've
trying to enable off-stack trampolines for a platform that doesn't
provide any such implementation.
* configure: Regenerate.
* libgcc-std.ver.in: Ditto.
* libgcc2.h (__builtin_nested_func_ptr_created): Declare.
(__builtin_nested_func_ptr_deleted): Ditto.
---
gcc/builtins.def | 2 +
gcc/common.opt | 4 ++
gcc/config.gcc | 7 +++
gcc/doc/invoke.texi | 14 +
gcc/tree-nested.c| 121 +--
gcc/tree.c | 17 ++
libgcc/configure | 26 +
libgcc/configure.ac | 17 ++
libgcc/libgcc-std.ver.in | 3 +
libgcc/libgcc2.h | 3 +
10 files changed, 197 insertions(+), 17 deletions(-)
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 45a09b4d42d..90a94a6dd0f 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -950,6 +950,8 @@ DEF_BUILTIN_STUB (BUILT_IN_ADJUST_TRAMPOLINE,
"__builtin_adjust_trampoline")
DEF_BUILTIN_STUB (BUILT_IN_INIT_DESCRIPTOR, "__builtin_init_descriptor")
DEF_BUILTIN_STUB (BUILT_IN_ADJUST_DESCRIPTOR, "__builtin_adjust_descriptor")
DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, "__builtin_nonlocal_goto")
+DEF_BUILTIN_STUB (BUILT_IN_NESTED_PTR_CREATED,
"__builtin_nested_func_ptr_created")
+DEF_BUILTIN_STUB (BUILT_IN_NESTED_PTR_DELETED,
"__builtin_nested_func_ptr_deleted")
/* Implementing __builtin_setjmp. */
DEF_BUILTIN_STUB (BUILT_IN_SETJMP_SETUP, "__builtin_setjmp_setup")
diff --git a/gcc/common.opt b/gcc/common.opt
index de9b848eda5..a97aeeb2165 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2149,6 +2149,10 @@ foffload-abi=
Common Joined RejectNegative Enum(offload_abi)
-foffload-abi=[lp64|ilp32] Set the ABI to use in an offload compiler.
+foff-stack-trampolines
+Common RejectNegative Var(flag_off_stack_trampolines)
Init(OFF_STACK_TRAMPOLINES_INIT)
+Generate trampolines in executable memory rather than executable stack.
+
Enum
Name(offload_abi) Type(enum offload_abi) UnknownError(unknown offload ABI %qs)
diff --git a/gcc/config.gcc b/gcc/config.gcc
index edd12655c4a..c479aa4cc44 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1070,6 +1070,13 @@ case ${target} in
;;
esac
+# Figure out if we need to enable -foff-stack-trampolines by default.
+case ${target} in
+*)
+ tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=0"
+ ;;
+esac
+
case ${target} in
aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems*)
tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h"
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2aba4c70b44..a5db65f8721 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -660,6 +660,7 @@ Objective-C and Objective-C++ Dialects}.
@gccoptlist{-fcall-saved-@var{reg} -fcall-used-@var{reg} @gol
-ffixed-@var{reg} -fexceptions @gol
-fnon-call-exceptions -fdelete-d