Implement the __builtin_nested_func_ptr_{created,deleted} functions for the aarch64-linux platform. This serves to exercise the infrastructure added in libgcc (--enable-off-stack-trampolines) and gcc (-foff-stack-trampolines) in supporting off-stack trampoline generation, and is intended primarily for demonstration and debugging purposes.
Co-authored-by: Andrew Burgess <andrew.burg...@embecosm.com> libgcc/ChangeLog: * config/aarch64/heap-trampoline.c: New file: Implement off-stack trampolines for aarch64. * config/aarch64/t-heap-trampoline: Add rule to build config/aarch64/heap-trampoline.c * config.host (aarch64-*-linux*): Handle --enable-off-stack-trampolines. * configure.ac (--enable-off-stack-trampolines): Permit setting for target aarch64-*-linux*. * configure: Regenerate. --- libgcc/config.host | 4 + libgcc/config/aarch64/heap-trampoline.c | 133 ++++++++++++++++++++++++ libgcc/config/aarch64/t-heap-trampoline | 21 ++++ libgcc/configure | 3 + libgcc/configure.ac | 3 + 5 files changed, 164 insertions(+) create mode 100644 libgcc/config/aarch64/heap-trampoline.c create mode 100644 libgcc/config/aarch64/t-heap-trampoline diff --git a/libgcc/config.host b/libgcc/config.host index 163cd4c4161..912477db7d9 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -388,6 +388,10 @@ aarch64*-*-linux*) tmake_file="${tmake_file} ${cpu_type}/t-aarch64" tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + 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*-*-vxworks7*) extra_parts="$extra_parts crtfastmath.o" diff --git a/libgcc/config/aarch64/heap-trampoline.c b/libgcc/config/aarch64/heap-trampoline.c new file mode 100644 index 00000000000..721a2bed400 --- /dev/null +++ b/libgcc/config/aarch64/heap-trampoline.c @@ -0,0 +1,133 @@ +#include <unistd.h> +#include <sys/mman.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +void *allocate_trampoline_page (void); +int get_trampolines_per_page (void); +struct tramp_ctrl_data *allocate_tramp_ctrl (struct tramp_ctrl_data *parent); +void *allocate_trampoline_page (void); + +void __builtin_nested_func_ptr_created (void *chain, void *func, void **dst); +void __builtin_nested_func_ptr_deleted (void); + +struct tramp_ctrl_data; +struct tramp_ctrl_data +{ + struct tramp_ctrl_data *prev; + + int free_trampolines; + + /* This will be pointing to an executable mmap'ed page. */ + struct aarch64_trampoline *trampolines; +}; + +struct aarch64_trampoline { + uint32_t insns[6]; + void *func_ptr; + void *chain_ptr; +}; + +int +get_trampolines_per_page (void) +{ + return getpagesize() / sizeof(struct aarch64_trampoline); +} + +static _Thread_local struct tramp_ctrl_data *tramp_ctrl_curr = NULL; + +void * +allocate_trampoline_page (void) +{ + void *page; + + page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC, + MAP_ANON | MAP_PRIVATE, 0, 0); + + return page; +} + +struct tramp_ctrl_data * +allocate_tramp_ctrl (struct tramp_ctrl_data *parent) +{ + struct tramp_ctrl_data *p = malloc (sizeof (struct tramp_ctrl_data)); + if (p == NULL) + return NULL; + + p->trampolines = allocate_trampoline_page (); + + if (p->trampolines == MAP_FAILED) + return NULL; + + p->prev = parent; + p->free_trampolines = get_trampolines_per_page(); + + return p; +} + +static const uint32_t aarch64_trampoline_insns[] = { + 0xd503245f, /* hint 34 */ + 0x580000b1, /* ldr x17, .+20 */ + 0x580000d2, /* ldr x18, .+24 */ + 0xd61f0220, /* br x17 */ + 0xd5033f9f, /* dsb sy */ + 0xd5033fdf /* isb */ +}; + +void +__builtin_nested_func_ptr_created (void *chain, void *func, void **dst) +{ + if (tramp_ctrl_curr == NULL) + { + tramp_ctrl_curr = allocate_tramp_ctrl (NULL); + if (tramp_ctrl_curr == NULL) + abort (); + } + + if (tramp_ctrl_curr->free_trampolines == 0) + { + void *tramp_ctrl = allocate_tramp_ctrl (tramp_ctrl_curr); + if (!tramp_ctrl) + abort (); + + tramp_ctrl_curr = tramp_ctrl; + } + + struct aarch64_trampoline *trampoline + = &tramp_ctrl_curr->trampolines[get_trampolines_per_page () + - tramp_ctrl_curr->free_trampolines]; + + memcpy (trampoline->insns, aarch64_trampoline_insns, + sizeof(aarch64_trampoline_insns)); + trampoline->func_ptr = func; + trampoline->chain_ptr = chain; + + tramp_ctrl_curr->free_trampolines -= 1; + + __builtin___clear_cache ((void *)trampoline->insns, + ((void *)trampoline->insns + sizeof(trampoline->insns))); + + *dst = &trampoline->insns; +} + +void +__builtin_nested_func_ptr_deleted (void) +{ + if (tramp_ctrl_curr == NULL) + abort (); + + tramp_ctrl_curr->free_trampolines += 1; + + if (tramp_ctrl_curr->free_trampolines == get_trampolines_per_page ()) + { + if (tramp_ctrl_curr->prev == NULL) + return; + + munmap (tramp_ctrl_curr->trampolines, getpagesize()); + struct tramp_ctrl_data *prev = tramp_ctrl_curr->prev; + free (tramp_ctrl_curr); + tramp_ctrl_curr = prev; + } +} diff --git a/libgcc/config/aarch64/t-heap-trampoline b/libgcc/config/aarch64/t-heap-trampoline new file mode 100644 index 00000000000..26b7756265e --- /dev/null +++ b/libgcc/config/aarch64/t-heap-trampoline @@ -0,0 +1,21 @@ +# Machine description for AArch64 architecture. +# Copyright (C) 2012-2021 Free Software Foundation, Inc. +# Contributed by ARM Ltd. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +LIB2ADD += $(srcdir)/config/aarch64/heap-trampoline.c diff --git a/libgcc/configure b/libgcc/configure index d9a74e3cc7c..5abcea8bed3 100755 --- a/libgcc/configure +++ b/libgcc/configure @@ -2264,6 +2264,9 @@ case "$target" in x86_64-*-linux* ) off_stack_trampolines=$enableval ;; + aarch64*-*-linux* ) + off_stack_trampolines=$enableval + ;; *) as_fn_error $? "Configure option --enable-off-stack-trampolines is not supported \ for this platform" "$LINENO" 5 diff --git a/libgcc/configure.ac b/libgcc/configure.ac index 4bec0a54493..c6eaceec957 100644 --- a/libgcc/configure.ac +++ b/libgcc/configure.ac @@ -75,6 +75,9 @@ case "$target" in x86_64-*-linux* ) off_stack_trampolines=$enableval ;; + aarch64*-*-linux* ) + off_stack_trampolines=$enableval + ;; *) AC_MSG_ERROR([Configure option --enable-off-stack-trampolines is not supported \ for this platform]) -- 2.30.1 (Apple Git-130)