From: Yury Khrustalev Date: Wed, 12 Mar 2025 15:28:24 +0000 (+0000) Subject: aarch64: add support for hwcap3,4 X-Git-Tag: glibc-2.42~158 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ea14d04e9a831874e40be39522145a45f1f4f8c7;p=thirdparty%2Fglibc.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 --- diff --git a/sysdeps/aarch64/dl-irel.h b/sysdeps/aarch64/dl-irel.h index ae402bc367..7bae3c3c49 100644 --- a/sysdeps/aarch64/dl-irel.h +++ b/sysdeps/aarch64/dl-irel.h @@ -21,11 +21,26 @@ #define _DL_IREL_H #include -#include #include -#include #include +#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); } diff --git a/sysdeps/aarch64/sys/ifunc.h b/sysdeps/aarch64/sys/ifunc.h index 7781b37a29..42d173195f 100644 --- a/sysdeps/aarch64/sys/ifunc.h +++ b/sysdeps/aarch64/sys/ifunc.h @@ -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; diff --git a/sysdeps/aarch64/tst-ifunc-arg-1.c b/sysdeps/aarch64/tst-ifunc-arg-1.c index b90c836000..9cc3d40c48 100644 --- a/sysdeps/aarch64/tst-ifunc-arg-1.c +++ b/sysdeps/aarch64/tst-ifunc-arg-1.c @@ -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; } diff --git a/sysdeps/aarch64/tst-ifunc-arg-2.c b/sysdeps/aarch64/tst-ifunc-arg-2.c index dac144d937..d9950f0e37 100644 --- a/sysdeps/aarch64/tst-ifunc-arg-2.c +++ b/sysdeps/aarch64/tst-ifunc-arg-2.c @@ -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; }