From 40fb13ac3de0dbd792d9fe09230dc0d0d4cde444 Mon Sep 17 00:00:00 2001 From: Yao Zihong Date: Mon, 20 Apr 2026 16:19:08 -0500 Subject: [PATCH] riscv: Add RVV strcpy for both multiarch and non-multiarch builds This patch adds an RVV-optimized implementation of strcpy for RISC-V and enables it for both multiarch (IFUNC) and non-multiarch builds. The implementation integrates Hau Hsu's 2023 RVV work under a unified ifunc-based framework. A vectorized version (__strcpy_vector) is added alongside the generic fallback (__strcpy_generic). The runtime resolver selects the RVV variant when RISCV_HWPROBE_KEY_IMA_EXT_0 reports vector support (RVV). Currently, the resolver still selects the RVV variant even when the RVV extension is disabled via prctl(). As a consequence, any process that has RVV disabled via prctl() will receive SIGILL when calling strcpy(). Co-authored-by: Hau Hsu Co-authored-by: Jerry Shih Signed-off-by: Yao Zihong Reviewed-by: Peter Bergner --- sysdeps/riscv/multiarch/strcpy-generic.c | 26 ++++++++ sysdeps/riscv/multiarch/strcpy-vector.S | 24 ++++++++ sysdeps/riscv/rvv/strcpy.S | 59 +++++++++++++++++++ .../unix/sysv/linux/riscv/multiarch/Makefile | 3 + .../linux/riscv/multiarch/ifunc-impl-list.c | 5 ++ .../unix/sysv/linux/riscv/multiarch/strcpy.c | 56 ++++++++++++++++++ 6 files changed, 173 insertions(+) create mode 100644 sysdeps/riscv/multiarch/strcpy-generic.c create mode 100644 sysdeps/riscv/multiarch/strcpy-vector.S create mode 100644 sysdeps/riscv/rvv/strcpy.S create mode 100644 sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c diff --git a/sysdeps/riscv/multiarch/strcpy-generic.c b/sysdeps/riscv/multiarch/strcpy-generic.c new file mode 100644 index 0000000000..8a29992570 --- /dev/null +++ b/sysdeps/riscv/multiarch/strcpy-generic.c @@ -0,0 +1,26 @@ +/* Re-include the default strcpy implementation. + Copyright (C) 2026 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 + . */ + +#include + +#if IS_IN(libc) +# define STRCPY __strcpy_generic +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(x) +# include +#endif diff --git a/sysdeps/riscv/multiarch/strcpy-vector.S b/sysdeps/riscv/multiarch/strcpy-vector.S new file mode 100644 index 0000000000..f5381a98ce --- /dev/null +++ b/sysdeps/riscv/multiarch/strcpy-vector.S @@ -0,0 +1,24 @@ +/* Re-include the RISC-V RVV based strcpy implementation. + Copyright (C) 2026 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 + . */ + +#if IS_IN(libc) +# define STRCPY __strcpy_vector +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) +# include +#endif diff --git a/sysdeps/riscv/rvv/strcpy.S b/sysdeps/riscv/rvv/strcpy.S new file mode 100644 index 0000000000..e73558d812 --- /dev/null +++ b/sysdeps/riscv/rvv/strcpy.S @@ -0,0 +1,59 @@ +/* RISC-V RVV based strcpy. + Copyright (C) 2026 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 + . */ + +#include +#include + +#ifndef STRCPY +# define STRCPY strcpy +#endif + +#define dst a0 +#define src a1 +#define dst_ptr a2 + +#define ivl a3 +#define cur_vl a4 +#define active_elem_pos a5 + +#define ELEM_LMUL_SETTING m1 +#define vmask1 v0 +#define vmask2 v1 +#define vstr1 v8 +#define vstr2 v16 + +ENTRY (STRCPY) +.option push +.option arch, +v + mv dst_ptr, dst +L(strcpy_loop): + vsetvli ivl, zero, e8, ELEM_LMUL_SETTING, ta, ma + vle8ff.v vstr1, (src) + vmseq.vx vmask2, vstr1, zero + csrr cur_vl, vl + vfirst.m active_elem_pos, vmask2 + vmsif.m vmask1, vmask2 + add src, src, cur_vl + vse8.v vstr1, (dst_ptr), vmask1.t + add dst_ptr, dst_ptr, cur_vl + bltz active_elem_pos, L(strcpy_loop) + + ret +.option pop +END (STRCPY) +libc_hidden_builtin_def (strcpy) diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile index 41ba27793d..c82693251a 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile @@ -9,6 +9,9 @@ sysdep_routines += \ strcat \ strcat-generic \ strcat-vector \ + strcpy \ + strcpy-generic \ + strcpy-vector \ # sysdep_routines CFLAGS-memcpy_noalignment.c += -mno-strict-align diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c index af64c04249..f4154bb8f7 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c @@ -58,5 +58,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, __strcat_vector) IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_generic)) + IFUNC_IMPL (i, name, strcpy, + IFUNC_IMPL_ADD (array, i, strcpy, rvv_enabled, + __strcpy_vector) + IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_generic)) + return 0; } diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c new file mode 100644 index 0000000000..ba47e8f89c --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c @@ -0,0 +1,56 @@ +/* Multiple versions of strcpy. + All versions must be listed in ifunc-impl-list.c. + Copyright (C) 2026 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 + . */ + +#if IS_IN (libc) +/* Redefine strcpy so that the compiler won't complain about the type + mismatch with the IFUNC selector in strong_alias, below. */ +# undef strcpy +# define strcpy __redirect_strcpy +# include +# include +# include +# include +# include + +extern __typeof (__redirect_strcpy) __libc_strcpy; + +extern __typeof (__redirect_strcpy) __strcpy_generic attribute_hidden; +extern __typeof (__redirect_strcpy) __strcpy_vector attribute_hidden; + +static inline __typeof (__redirect_strcpy) * +select_strcpy_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func) +{ + unsigned long long int v; + if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_IMA_EXT_0, &v) == 0 + && (v & RISCV_HWPROBE_IMA_V) == RISCV_HWPROBE_IMA_V) + return __strcpy_vector; + return __strcpy_generic; +} + +riscv_libc_ifunc (__libc_strcpy, select_strcpy_ifunc); + +# undef strcpy +strong_alias (__libc_strcpy, strcpy); +# ifdef SHARED +__hidden_ver1 (strcpy, __GI_strcpy, __redirect_strcpy) + __attribute__ ((visibility ("hidden"))) __attribute_copy__ (strcpy); +# endif +#else +# include +#endif -- 2.47.3