[3/4] Add aarch64-linux support for off-stack trampolines
Commit Message
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.burgess@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
Comments
On 11/13/2021 2:45 AM, Maxim Blinov wrote:
> 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.burgess@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.
I'd leave this to the aarch64 maintainers. I don't see anything
particularly bad. I'd probably drop the all the configure time
selectability stuff and just have the aarch64 darwin default to this
implementation if the basic concept goes forward.
jeff
@@ -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"
new file mode 100644
@@ -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;
+ }
+}
new file mode 100644
@@ -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
@@ -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
@@ -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])