public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc] aarch64: new ifunc resolver ABI
@ 2019-07-04 10:16 Szabolcs Nagy
  0 siblings, 0 replies; only message in thread
From: Szabolcs Nagy @ 2019-07-04 10:16 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=2b8a3c86e7606cf1b0a997dad8af2d45ae8989c3

commit 2b8a3c86e7606cf1b0a997dad8af2d45ae8989c3
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Tue Apr 23 15:59:34 2019 +0100

    aarch64: new ifunc resolver ABI
    
    Passing a second argument to the ifunc resolver allows accessing
    AT_HWCAP2 values from the resolver. AArch64 will start using AT_HWCAP2
    on linux because for ilp32 to remain compatible with lp64 ABI no more
    than 32bit hwcap flags can be in AT_HWCAP which is already used up.
    
    Currently the relocation ordering logic does not guarantee that ifunc
    resolvers can call libc apis or access libc objects, so only the
    resolver arguments and runtime environment dependent instructions can
    be used to do the dispatch (this affects ifunc resolvers outside of
    the libc).
    
    Since ifunc resolver is target specific and only supposed to be
    called by the dynamic linker, the call ABI can be changed in a
    backward compatible way:
    
    Old call ABI passed hwcap as uint64_t, new abi sets the
    _IFUNC_ARG_HWCAP flag in the hwcap and passes a second argument
    that's a pointer to an extendible struct. A resolver has to check
    the _IFUNC_ARG_HWCAP flag before accessing the second argument.
    
    The new sys/ifunc.h installed header has the definitions for the
    new ABI, everything is in the implementation reserved namespace.
    
    An alternative approach is to try to support extern calls from ifunc
    resolvers such as getauxval, but that seems non-trivial
    https://sourceware.org/ml/libc-alpha/2017-01/msg00468.html
    
    	* sysdeps/aarch64/Makefile: Install sys/ifunc.h and add tests.
    	* sysdeps/aarch64/dl-irel.h (elf_ifunc_invoke): Update to new ABI.
    	* sysdeps/aarch64/sys/ifunc.h: New file.
    	* sysdeps/aarch64/tst-ifunc-arg-1.c: New file.
    	* sysdeps/aarch64/tst-ifunc-arg-2.c: New file.

Diff:
---
 ChangeLog                         |  8 +++++
 sysdeps/aarch64/Makefile          |  6 ++++
 sysdeps/aarch64/dl-irel.h         |  9 +++++-
 sysdeps/aarch64/sys/ifunc.h       | 42 +++++++++++++++++++++++++
 sysdeps/aarch64/tst-ifunc-arg-1.c | 63 +++++++++++++++++++++++++++++++++++++
 sysdeps/aarch64/tst-ifunc-arg-2.c | 66 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 193 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 21e6374..fe5fd79 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2019-07-04  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* sysdeps/aarch64/Makefile: Install sys/ifunc.h and add tests.
+	* sysdeps/aarch64/dl-irel.h (elf_ifunc_invoke): Update to new ABI.
+	* sysdeps/aarch64/sys/ifunc.h: New file.
+	* sysdeps/aarch64/tst-ifunc-arg-1.c: New file.
+	* sysdeps/aarch64/tst-ifunc-arg-2.c: New file.
+
 2019-07-01  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #20188]
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index 94baaf5..9cb1410 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -3,6 +3,8 @@ long-double-fcts = yes
 ifeq ($(subdir),elf)
 sysdep-dl-routines += tlsdesc dl-tlsdesc
 gen-as-const-headers += dl-link.sym
+
+tests-internal += tst-ifunc-arg-1 tst-ifunc-arg-2
 endif
 
 ifeq ($(subdir),csu)
@@ -16,3 +18,7 @@ endif
 ifeq ($(subdir),math)
 CPPFLAGS += -I../soft-fp
 endif
+
+ifeq ($(subdir),misc)
+sysdep_headers += sys/ifunc.h
+endif
diff --git a/sysdeps/aarch64/dl-irel.h b/sysdeps/aarch64/dl-irel.h
index 4f669e7..8db6ef5 100644
--- a/sysdeps/aarch64/dl-irel.h
+++ b/sysdeps/aarch64/dl-irel.h
@@ -24,6 +24,7 @@
 #include <unistd.h>
 #include <ldsodefs.h>
 #include <sysdep.h>
+#include <sys/ifunc.h>
 
 #define ELF_MACHINE_IRELA	1
 
@@ -31,7 +32,13 @@ static inline ElfW(Addr)
 __attribute ((always_inline))
 elf_ifunc_invoke (ElfW(Addr) addr)
 {
-  return ((ElfW(Addr) (*) (uint64_t)) (addr)) (GLRO(dl_hwcap));
+  __ifunc_arg_t arg;
+
+  arg._size = sizeof (arg);
+  arg._hwcap = GLRO(dl_hwcap);
+  arg._hwcap2 = GLRO(dl_hwcap2);
+  return ((ElfW(Addr) (*) (uint64_t, const __ifunc_arg_t *)) (addr))
+	 (GLRO(dl_hwcap) | _IFUNC_ARG_HWCAP, &arg);
 }
 
 static inline void
diff --git a/sysdeps/aarch64/sys/ifunc.h b/sysdeps/aarch64/sys/ifunc.h
new file mode 100644
index 0000000..ef200e9
--- /dev/null
+++ b/sysdeps/aarch64/sys/ifunc.h
@@ -0,0 +1,42 @@
+/* Definitions used by AArch64 indirect function resolvers.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_IFUNC_H
+#define _SYS_IFUNC_H
+
+/* A second argument is passed to the ifunc resolver.  */
+#define _IFUNC_ARG_HWCAP	(1ULL << 62)
+
+/* The prototype of a gnu indirect function resolver on AArch64 is
+
+     ElfW(Addr) ifunc_resolver (uint64_t, const __ifunc_arg_t *);
+
+   the first argument should have the _IFUNC_ARG_HWCAP bit set and
+   the remaining bits should match the AT_HWCAP settings.  */
+
+/* Second argument to an ifunc resolver.  */
+struct __ifunc_arg_t
+{
+  unsigned long _size; /* Size of the struct, so it can grow.  */
+  unsigned long _hwcap;
+  unsigned long _hwcap2;
+};
+
+typedef struct __ifunc_arg_t __ifunc_arg_t;
+
+#endif
diff --git a/sysdeps/aarch64/tst-ifunc-arg-1.c b/sysdeps/aarch64/tst-ifunc-arg-1.c
new file mode 100644
index 0000000..cedd987
--- /dev/null
+++ b/sysdeps/aarch64/tst-ifunc-arg-1.c
@@ -0,0 +1,63 @@
+/* Test STT_GNU_IFUNC resolver with second argument.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+#include <sys/auxv.h>
+#include <sys/ifunc.h>
+#include <support/check.h>
+
+static int
+one (void)
+{
+  return 1;
+}
+
+static uint64_t saved_arg1;
+static __ifunc_arg_t saved_arg2;
+
+/* extern visible ifunc symbol.  */
+int
+foo (void);
+
+void *
+foo_ifunc (uint64_t, const __ifunc_arg_t *) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+inhibit_stack_protector
+foo_ifunc (uint64_t arg1, const __ifunc_arg_t *arg2)
+{
+  saved_arg1 = arg1;
+  if (arg1 & _IFUNC_ARG_HWCAP)
+      saved_arg2 = *arg2;
+  return (void *) one;
+}
+
+static int
+do_test (void)
+{
+  TEST_VERIFY (foo () == 1);
+  TEST_VERIFY (saved_arg1 & _IFUNC_ARG_HWCAP);
+  TEST_COMPARE ((uint32_t)saved_arg1, (uint32_t)getauxval (AT_HWCAP));
+  TEST_COMPARE (saved_arg2._size, sizeof (__ifunc_arg_t));
+  TEST_COMPARE (saved_arg2._hwcap, getauxval (AT_HWCAP));
+  TEST_COMPARE (saved_arg2._hwcap2, getauxval (AT_HWCAP2));
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/aarch64/tst-ifunc-arg-2.c b/sysdeps/aarch64/tst-ifunc-arg-2.c
new file mode 100644
index 0000000..9564818
--- /dev/null
+++ b/sysdeps/aarch64/tst-ifunc-arg-2.c
@@ -0,0 +1,66 @@
+/* Test R_*_IRELATIVE resolver with second argument.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+#include <sys/auxv.h>
+#include <sys/ifunc.h>
+#include <support/check.h>
+
+static int
+one (void)
+{
+  return 1;
+}
+
+static uint64_t saved_arg1;
+static __ifunc_arg_t saved_arg2;
+
+/* local ifunc symbol.  */
+int
+__attribute__ ((visibility ("hidden")))
+foo (void);
+
+static void *
+__attribute__ ((used))
+foo_ifunc (uint64_t, const __ifunc_arg_t *) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+static void *
+__attribute__ ((used))
+inhibit_stack_protector
+foo_ifunc (uint64_t arg1, const __ifunc_arg_t *arg2)
+{
+  saved_arg1 = arg1;
+  if (arg1 & _IFUNC_ARG_HWCAP)
+      saved_arg2 = *arg2;
+  return (void *) one;
+}
+
+static int
+do_test (void)
+{
+  TEST_VERIFY (foo () == 1);
+  TEST_VERIFY (saved_arg1 & _IFUNC_ARG_HWCAP);
+  TEST_COMPARE ((uint32_t)saved_arg1, (uint32_t)getauxval (AT_HWCAP));
+  TEST_COMPARE (saved_arg2._size, sizeof (__ifunc_arg_t));
+  TEST_COMPARE (saved_arg2._hwcap, getauxval (AT_HWCAP));
+  TEST_COMPARE (saved_arg2._hwcap2, getauxval (AT_HWCAP2));
+  return 0;
+}
+
+#include <support/test-driver.c>


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-07-04 10:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-04 10:16 [glibc] aarch64: new ifunc resolver ABI Szabolcs Nagy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).