mirror of git://sourceware.org/git/glibc.git
aarch64: add support for hwcap3,4
Add basic support for hwcap3 and hwcap4 in dynamic loader and ifunc resolvers. Describe new backward-compatible prototype for GNU indirect function resolvers that use a pointer to uint64_t array in stead of a pointer to the __ifunc_arg_t struct. This patch also adds macro _IFUNC_HWCAP_MAX to specify current number of hwcap elements. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
parent
25f1d94576
commit
ea14d04e9a
|
|
@ -21,11 +21,26 @@
|
|||
#define _DL_IREL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <sysdep.h>
|
||||
#include <sys/ifunc.h>
|
||||
|
||||
#define _IFUNC_ARG_SIZE_VER0 24 /* sizeof 1st published __ifunc_arg_t */
|
||||
#define _IFUNC_ARG_SIZE_VER1 40 /* sizeof 2nd published __ifunc_arg_t */
|
||||
|
||||
#define sizeof_field(TYPE, MEMBER) sizeof ((((TYPE *)0)->MEMBER))
|
||||
#define offsetofend(TYPE, MEMBER) \
|
||||
(offsetof (TYPE, MEMBER) + sizeof_field (TYPE, MEMBER))
|
||||
|
||||
_Static_assert (sizeof (__ifunc_arg_t) == _IFUNC_ARG_SIZE_VER1,
|
||||
"sizeof (__ifunc_arg_t) != _IFUNC_ARG_SIZE_VER1");
|
||||
|
||||
_Static_assert (_IFUNC_ARG_SIZE_VER1
|
||||
== (_IFUNC_HWCAP_MAX + 1) * sizeof (unsigned long),
|
||||
"_IFUNC_ARG_SIZE_VER1 and _IFUNC_HWCAP_MAX mismatch");
|
||||
|
||||
#undef offsetofend
|
||||
#undef sizeof_field
|
||||
|
||||
#define ELF_MACHINE_IRELA 1
|
||||
|
||||
static inline ElfW(Addr)
|
||||
|
|
@ -37,6 +52,8 @@ elf_ifunc_invoke (ElfW(Addr) addr)
|
|||
arg._size = sizeof (arg);
|
||||
arg._hwcap = GLRO(dl_hwcap);
|
||||
arg._hwcap2 = GLRO(dl_hwcap2);
|
||||
arg._hwcap3 = GLRO(dl_hwcap3);
|
||||
arg._hwcap4 = GLRO(dl_hwcap4);
|
||||
return ((ElfW(Addr) (*) (uint64_t, const __ifunc_arg_t *)) (addr))
|
||||
(GLRO(dl_hwcap) | _IFUNC_ARG_HWCAP, &arg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,19 +22,41 @@
|
|||
/* 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
|
||||
/* Maximum number of HWCAP elements that are currently supported. */
|
||||
#define _IFUNC_HWCAP_MAX 4
|
||||
|
||||
/* The prototype of a GNU indirect function resolver on AArch64 is
|
||||
|
||||
ElfW(Addr) ifunc_resolver (uint64_t, const uint64_t *);
|
||||
|
||||
The following prototype is also compatible:
|
||||
|
||||
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. */
|
||||
The first argument might have the _IFUNC_ARG_HWCAP bit set and
|
||||
the remaining bits should match the AT_HWCAP settings.
|
||||
|
||||
If the _IFUNC_ARG_HWCAP bit is set in the first argument, then
|
||||
the second argument is passed to the resolver function. In
|
||||
this case, the second argument is a const pointer to a buffer
|
||||
that allows to access all available HWCAP elements.
|
||||
|
||||
This buffer has its size in bytes at offset 0. The HWCAP elements
|
||||
are available at offsets 8, 16, 24, 32... respectively for AT_HWCAP,
|
||||
AT_HWCAP2, AT_HWCAP3, AT_HWCAP4... (these offsets are multiples of
|
||||
sizeof (unsigned long)).
|
||||
|
||||
Indirect function resolvers must check availability of HWCAP
|
||||
elements at runtime before accessing them using the size of the
|
||||
buffer. */
|
||||
|
||||
/* Second argument to an ifunc resolver. */
|
||||
struct __ifunc_arg_t
|
||||
{
|
||||
unsigned long _size; /* Size of the struct, so it can grow. */
|
||||
unsigned long _size; /* Size of the struct, so it can grow. */
|
||||
unsigned long _hwcap;
|
||||
unsigned long _hwcap2;
|
||||
unsigned long _hwcap2; /* End of 1st published struct. */
|
||||
unsigned long _hwcap3;
|
||||
unsigned long _hwcap4; /* End of 2nd published struct. */
|
||||
};
|
||||
|
||||
typedef struct __ifunc_arg_t __ifunc_arg_t;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ do_test (void)
|
|||
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));
|
||||
TEST_COMPARE (saved_arg2._hwcap3, getauxval (AT_HWCAP3));
|
||||
TEST_COMPARE (saved_arg2._hwcap4, getauxval (AT_HWCAP4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ do_test (void)
|
|||
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));
|
||||
TEST_COMPARE (saved_arg2._hwcap3, getauxval (AT_HWCAP3));
|
||||
TEST_COMPARE (saved_arg2._hwcap4, getauxval (AT_HWCAP4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue