[v9,3/6] riscv: Add __riscv_hwprobe pointer to ifunc calls

Message ID 20231130183239.598100-4-evan@rivosinc.com
State Superseded
Headers
Series RISC-V: ifunced memcpy using new kernel hwprobe interface |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Testing passed

Commit Message

Evan Green Nov. 30, 2023, 6:32 p.m. UTC
  The new __riscv_hwprobe() function is designed to be used by ifunc
selector functions. This presents a challenge for applications and
libraries, as ifunc selectors are invoked before all relocations have
been performed, so an external call to __riscv_hwprobe() from an ifunc
selector won't work. To address this, pass a pointer to the
__riscv_hwprobe() vDSO function into ifunc selectors as the second
argument (alongside dl_hwcap, which was already being passed).

Include a typedef as well for convenience, so that ifunc users don't
have to go through contortions to call this routine. Users will need to
remember to check the second argument for NULL, both to account for
older glibcs that don't pass the function, and older kernels that don't
have the vDSO pointer.

Signed-off-by: Evan Green <evan@rivosinc.com>

---

(no changes since v7)

Changes in v7:
 - Remove __THROW from function pointer type, as it creates warnings
   together with __fortified_attr_access.

 sysdeps/riscv/dl-irel.h                     |  8 ++++----
 sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h | 10 ++++++++++
 2 files changed, 14 insertions(+), 4 deletions(-)
  

Comments

enh Dec. 6, 2023, 12:31 a.m. UTC | #1
makes sense to me. i've made the equivalent change to bionic for
source compatibility in
https://android-review.googlesource.com/c/platform/bionic/+/2860689
(and thanks to your earlier "lets pass a null void* as our last
argument", it's more backwards compatible than any other ifunc
resolver change we've ever made).

On Thu, Nov 30, 2023 at 10:33 AM Evan Green <evan@rivosinc.com> wrote:
>
> The new __riscv_hwprobe() function is designed to be used by ifunc
> selector functions. This presents a challenge for applications and
> libraries, as ifunc selectors are invoked before all relocations have
> been performed, so an external call to __riscv_hwprobe() from an ifunc
> selector won't work. To address this, pass a pointer to the
> __riscv_hwprobe() vDSO function into ifunc selectors as the second
> argument (alongside dl_hwcap, which was already being passed).
>
> Include a typedef as well for convenience, so that ifunc users don't
> have to go through contortions to call this routine. Users will need to
> remember to check the second argument for NULL, both to account for
> older glibcs that don't pass the function, and older kernels that don't
> have the vDSO pointer.
>
> Signed-off-by: Evan Green <evan@rivosinc.com>
>
> ---
>
> (no changes since v7)
>
> Changes in v7:
>  - Remove __THROW from function pointer type, as it creates warnings
>    together with __fortified_attr_access.
>
>  sysdeps/riscv/dl-irel.h                     |  8 ++++----
>  sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h | 10 ++++++++++
>  2 files changed, 14 insertions(+), 4 deletions(-)
>
> diff --git a/sysdeps/riscv/dl-irel.h b/sysdeps/riscv/dl-irel.h
> index eaeec5467c..2147504458 100644
> --- a/sysdeps/riscv/dl-irel.h
> +++ b/sysdeps/riscv/dl-irel.h
> @@ -31,10 +31,10 @@ static inline ElfW(Addr)
>  __attribute ((always_inline))
>  elf_ifunc_invoke (ElfW(Addr) addr)
>  {
> -  /* The second argument is a void pointer to preserve the extension
> -     fexibility.  */
> -  return ((ElfW(Addr) (*) (uint64_t, void *)) (addr))
> -        (GLRO(dl_hwcap), NULL);
> +  /* The third argument is a void pointer to preserve the extension
> +     flexibility.  */
> +  return ((ElfW(Addr) (*) (uint64_t, void *, void *)) (addr))
> +        (GLRO(dl_hwcap), GLRO(dl_vdso_riscv_hwprobe), NULL);
>  }
>
>  static inline void
> diff --git a/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h b/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h
> index aa189a4818..fd3be5a411 100644
> --- a/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h
> +++ b/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h
> @@ -67,6 +67,16 @@ extern int __riscv_hwprobe (struct riscv_hwprobe *__pairs, size_t __pair_count,
>       __fortified_attr_access (__read_write__, 1, 2)
>       __fortified_attr_access (__read_only__, 4, 3);
>
> +/* A pointer to the __riscv_hwprobe vDSO function is passed as the second
> +   argument to ifunc selector routines. Include a function pointer type for
> +   convenience in calling the function in those settings. */
> +typedef int (*__riscv_hwprobe_t) (struct riscv_hwprobe *__pairs, size_t __pair_count,
> +                                 size_t __cpu_count, unsigned long int *__cpus,
> +                                 unsigned int __flags)
> +     __nonnull ((1)) __wur
> +     __fortified_attr_access (__read_write__, 1, 2)
> +     __fortified_attr_access (__read_only__, 4, 3);
> +
>  __END_DECLS
>
>  #endif /* sys/hwprobe.h */
> --
> 2.34.1
>
  

Patch

diff --git a/sysdeps/riscv/dl-irel.h b/sysdeps/riscv/dl-irel.h
index eaeec5467c..2147504458 100644
--- a/sysdeps/riscv/dl-irel.h
+++ b/sysdeps/riscv/dl-irel.h
@@ -31,10 +31,10 @@  static inline ElfW(Addr)
 __attribute ((always_inline))
 elf_ifunc_invoke (ElfW(Addr) addr)
 {
-  /* The second argument is a void pointer to preserve the extension
-     fexibility.  */
-  return ((ElfW(Addr) (*) (uint64_t, void *)) (addr))
-	 (GLRO(dl_hwcap), NULL);
+  /* The third argument is a void pointer to preserve the extension
+     flexibility.  */
+  return ((ElfW(Addr) (*) (uint64_t, void *, void *)) (addr))
+	 (GLRO(dl_hwcap), GLRO(dl_vdso_riscv_hwprobe), NULL);
 }
 
 static inline void
diff --git a/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h b/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h
index aa189a4818..fd3be5a411 100644
--- a/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h
+++ b/sysdeps/unix/sysv/linux/riscv/sys/hwprobe.h
@@ -67,6 +67,16 @@  extern int __riscv_hwprobe (struct riscv_hwprobe *__pairs, size_t __pair_count,
      __fortified_attr_access (__read_write__, 1, 2)
      __fortified_attr_access (__read_only__, 4, 3);
 
+/* A pointer to the __riscv_hwprobe vDSO function is passed as the second
+   argument to ifunc selector routines. Include a function pointer type for
+   convenience in calling the function in those settings. */
+typedef int (*__riscv_hwprobe_t) (struct riscv_hwprobe *__pairs, size_t __pair_count,
+				  size_t __cpu_count, unsigned long int *__cpus,
+				  unsigned int __flags)
+     __nonnull ((1)) __wur
+     __fortified_attr_access (__read_write__, 1, 2)
+     __fortified_attr_access (__read_only__, 4, 3);
+
 __END_DECLS
 
 #endif /* sys/hwprobe.h */