Hi all, apologies for forgetting to add the cover letter.

The motivation of this work is to provide (limited) support for GCC
nested function trampolines on targets that do not have an executable
stack. This code has been (roughly) tested by creating several
thousand nested functions (i.e. enough to force allocation of a new
page), making sure all the nested functions execute correctly, and
consequently returning back up and ensuring that the pages are freed
when there are no more active trampolines in them.

I was provided the initial design and prototype implementation by
Andrew Burgess, and have since refactored the code to support
allocation/deallocation of trampoline pages, and added AArch64
Linux/Darwin support.

One of the limitations of the implementation in its current state is
the inability to track longjmps. There has been some discussion about
instrumenting calls to setjmp/longjmp so that the state of trampolines
is correctly tracked and freed when necessary, however that hasn't
been worked on yet.

On Sat, 13 Nov 2021 at 09:45, Maxim Blinov <maxim.bli...@embecosm.com> wrote:
>
> Note: This patch is not yet ready for trunk as its dependent on some
> patches that are not-yet-upstream, however it serves as motivation for
> the previous patch(es) which are independent.
>
> ----
>
> Implement the __builtin_nested_func_ptr_{created,deleted} functions
> for the aarch64-darwin platform. For this platform
> --enable-off-stack-trampolines is enabled by default, and
> -foff-stack-trampolines is enabled by default if the host MacOS
> operating system version is 11.x or greater.
>
> Co-authored-by: Andrew Burgess <andrew.burg...@embecosm.com>
>
> libgcc/ChangeLog:
>
>         * config/aarch64/heap-trampoline.c (allocate_trampoline_page):
>         Request for MAP_JIT in the case of __APPLE__.
>         Provide __APPLE__ variant of aarch64_trampoline_insns that uses
>         x16 as the chain pointer.
>         (__builtin_nested_func_ptr_created): Call
>         pthread_jit_write_protect_np() to toggle read/write permission on
>         page.
>         * config.host (aarch64*-*darwin* | arm64*-*darwin*): Handle
>         --enable-off-stack-trampolines.
>         * configure.ac (--enable-off-stack-trampolines): Permit setting
>         for target aarch64*-*darwin* | arm64*-*darwin*, and set default to
>         enabled.
>         * configure: Regenerate.
> ---
>  gcc/config.gcc                          |  7 +++++
>  libgcc/config.host                      |  4 +++
>  libgcc/config/aarch64/heap-trampoline.c | 36 +++++++++++++++++++++++++
>  libgcc/configure                        |  6 +++++
>  libgcc/configure.ac                     |  6 +++++
>  5 files changed, 59 insertions(+)
>
> diff --git a/gcc/config.gcc b/gcc/config.gcc
> index 031be563c5d..c13f7629d44 100644
> --- a/gcc/config.gcc
> +++ b/gcc/config.gcc
> @@ -1072,6 +1072,13 @@ esac
>
>  # Figure out if we need to enable -foff-stack-trampolines by default.
>  case ${target} in
> +aarch64*-*darwin* | arm64*-*darwin*)
> +  if test ${macos_maj} = 11 || test ${macos_maj} = 12; then
> +    tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=1"
> +  else
> +    tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=0"
> +  fi
> +  ;;
>  *)
>    tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=0"
>    ;;
> diff --git a/libgcc/config.host b/libgcc/config.host
> index d1a491d27e7..3c536b0928a 100644
> --- a/libgcc/config.host
> +++ b/libgcc/config.host
> @@ -414,6 +414,10 @@ aarch64*-*darwin* | arm64*-*darwin* )
>         tmake_file="${tmake_file} t-crtfm"
>         # No soft float for now because our long double is DF not TF.
>         md_unwind_header=aarch64/aarch64-unwind.h
> +       if test x$off_stack_trampolines = xyes; then
> +           extra_parts="$extra_parts heap-trampoline.o"
> +           tmake_file="${tmake_file} ${cpu_type}/t-heap-trampoline"
> +       fi
>         ;;
>  aarch64*-*-freebsd*)
>         extra_parts="$extra_parts crtfastmath.o"
> diff --git a/libgcc/config/aarch64/heap-trampoline.c 
> b/libgcc/config/aarch64/heap-trampoline.c
> index 721a2bed400..6994602beaf 100644
> --- a/libgcc/config/aarch64/heap-trampoline.c
> +++ b/libgcc/config/aarch64/heap-trampoline.c
> @@ -5,6 +5,9 @@
>  #include <stdio.h>
>  #include <string.h>
>
> +/* For pthread_jit_write_protect_np */
> +#include <pthread.h>
> +
>  void *allocate_trampoline_page (void);
>  int get_trampolines_per_page (void);
>  struct tramp_ctrl_data *allocate_tramp_ctrl (struct tramp_ctrl_data *parent);
> @@ -43,8 +46,15 @@ allocate_trampoline_page (void)
>  {
>    void *page;
>
> +#if defined(__gnu_linux__)
>    page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
>                MAP_ANON | MAP_PRIVATE, 0, 0);
> +#elif defined(__APPLE__)
> +  page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
> +              MAP_ANON | MAP_PRIVATE | MAP_JIT, 0, 0);
> +#else
> +  page = MAP_FAILED;
> +#endif
>
>    return page;
>  }
> @@ -67,6 +77,7 @@ allocate_tramp_ctrl (struct tramp_ctrl_data *parent)
>    return p;
>  }
>
> +#if defined(__gnu_linux__)
>  static const uint32_t aarch64_trampoline_insns[] = {
>    0xd503245f, /* hint    34 */
>    0x580000b1, /* ldr     x17, .+20 */
> @@ -76,6 +87,20 @@ static const uint32_t aarch64_trampoline_insns[] = {
>    0xd5033fdf /* isb */
>  };
>
> +#elif defined(__APPLE__)
> +static const uint32_t aarch64_trampoline_insns[] = {
> +  0xd503245f, /* hint    34 */
> +  0x580000b1, /* ldr     x17, .+20 */
> +  0x580000d0, /* ldr     x16, .+24 */
> +  0xd61f0220, /* br      x17 */
> +  0xd5033f9f, /* dsb     sy */
> +  0xd5033fdf /* isb */
> +};
> +
> +#else
> +#error "Unsupported AArch64 platform for heap trampolines"
> +#endif
> +
>  void
>  __builtin_nested_func_ptr_created (void *chain, void *func, void **dst)
>  {
> @@ -99,11 +124,22 @@ __builtin_nested_func_ptr_created (void *chain, void 
> *func, void **dst)
>      = &tramp_ctrl_curr->trampolines[get_trampolines_per_page ()
>                                     - tramp_ctrl_curr->free_trampolines];
>
> +#if defined(__APPLE__)
> +  /* Disable write protection for the MAP_JIT regions in this thread (see
> +     
> https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon)
>  */
> +  pthread_jit_write_protect_np (0);
> +#endif
> +
>    memcpy (trampoline->insns, aarch64_trampoline_insns,
>           sizeof(aarch64_trampoline_insns));
>    trampoline->func_ptr = func;
>    trampoline->chain_ptr = chain;
>
> +#if defined(__APPLE__)
> +  /* Re-enable write protection.  */
> +  pthread_jit_write_protect_np (1);
> +#endif
> +
>    tramp_ctrl_curr->free_trampolines -= 1;
>
>    __builtin___clear_cache ((void *)trampoline->insns,
> diff --git a/libgcc/configure b/libgcc/configure
> index 5abcea8bed3..35cdf8f8c05 100755
> --- a/libgcc/configure
> +++ b/libgcc/configure
> @@ -2267,6 +2267,9 @@ case "$target" in
>    aarch64*-*-linux* )
>      off_stack_trampolines=$enableval
>      ;;
> +  aarch64*-*darwin* | arm64*-*darwin* )
> +    off_stack_trampolines=$enableval
> +    ;;
>    *)
>      as_fn_error $? "Configure option --enable-off-stack-trampolines is not 
> supported \
>  for this platform" "$LINENO" 5
> @@ -2276,6 +2279,9 @@ esac
>  else
>
>  case "$target" in
> +  aarch64*-*darwin* | arm64*-*darwin* )
> +    off_stack_trampolines=yes
> +    ;;
>    *)
>      off_stack_trampolines=no
>      ;;
> diff --git a/libgcc/configure.ac b/libgcc/configure.ac
> index c6eaceec957..3b129f1a4b8 100644
> --- a/libgcc/configure.ac
> +++ b/libgcc/configure.ac
> @@ -78,6 +78,9 @@ case "$target" in
>    aarch64*-*-linux* )
>      off_stack_trampolines=$enableval
>      ;;
> +  aarch64*-*darwin* | arm64*-*darwin* )
> +    off_stack_trampolines=$enableval
> +    ;;
>    *)
>      AC_MSG_ERROR([Configure option --enable-off-stack-trampolines is not 
> supported \
>  for this platform])
> @@ -85,6 +88,9 @@ for this platform])
>      ;;
>  esac],[
>  case "$target" in
> +  aarch64*-*darwin* | arm64*-*darwin* )
> +    off_stack_trampolines=yes
> +    ;;
>    *)
>      off_stack_trampolines=no
>      ;;
> --
> 2.30.1 (Apple Git-130)
>

Reply via email to