[PATCH v2] RISC-V: Fix SIGSEGV of --static-pie binaries on riscv64 [BZ #33911]
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Fri Mar 6 16:42:42 GMT 2026
On 06/03/26 12:10, daichengrong wrote:
> This patch fixes a SIGSEGV observed in --static-pie binaries on riscv64,
> as reported in BZ #33911. The root cause is a recent memset optimization
> that introduced incorrect behavior when resolving symbols for static PIE
> executables.
>
> Problem:
> --------
> In static PIE binaries, an early call to ifunc memset could use GOT entries
> that were not yet properly initialized. This results in jumping to
> invalid addresses, causing SIGSEGV.
This is exactly what <dl-symbol-redir-ifunc.h> is for.
>
> Solution:
> ---------
> This patch ensures that GOT entries for static PIE binaries are
> correctly set up before ifunc memset calls occur.
Sorry, but this kind of code duplication for arch-specific workarounds are not
acceptable. And this issue is not RISCV specific, other ABIs might implement
memset through ifunc and being subject to the very issue if the compiler starts
to optimize more construction to libcalls.
One solution could to implement ELF_MACHINE_BEFORE_RTLD_RELOC for RISCV, or
restructure the generic elf/dl-reloc-static-pie.c to add another arch-specific
hook. Worse scenario, we just build the TU with -ftree-loop-distribute-patterns
to avoid any libcalls (and I would prefer to avoid it because this is a gcc
specific fix).
In any case, I think we can just fix it with the following patch. At least on
qemu I don't see any more SEGFAULTs with -Os.
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index bdff2b5ee2..63ce609024 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -25,6 +25,7 @@
#include <dl-machine.h>
#include <dl-debug.h>
+#include <dl-symbol-redir-ifunc.h>
#define RESOLVE_MAP(map, scope, sym, version, flags) map
#include "dynamic-link.h"
diff --git a/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h b/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h
index 24b78711e3..69a0790838 100644
--- a/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h
+++ b/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h
@@ -21,6 +21,7 @@
#ifndef SHARED
asm ("memset = __memset_generic");
+asm ("memcpy = __memcpy_generic");
#endif
#endif
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index a865090a53..a033ea9569 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
@@ -11,4 +11,5 @@ sysdep_routines += \
CFLAGS-memcpy_noalignment.c += -mno-strict-align
# Called during static initialization
CFLAGS-memset-generic.c += $(no-stack-protector)
+CFLAGS-memcpy-generic.c += $(no-stack-protector)
endif
>
> Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
> ---
> sysdeps/riscv/cpu-features.c | 88 ++++++++++++++++++++++++++++++++++++
> sysdeps/riscv/dl-machine.h | 4 +-
> sysdeps/riscv/libc-start.c | 34 ++++++++++++++
> 3 files changed, 124 insertions(+), 2 deletions(-)
> create mode 100644 sysdeps/riscv/cpu-features.c
> create mode 100644 sysdeps/riscv/libc-start.c
>
> diff --git a/sysdeps/riscv/cpu-features.c b/sysdeps/riscv/cpu-features.c
> new file mode 100644
> index 0000000000..56f694c31f
> --- /dev/null
> +++ b/sysdeps/riscv/cpu-features.c
> @@ -0,0 +1,88 @@
> +/* Initialize CPU feature data.
> + This file is part of the GNU C Library.
> + Copyright (C) 2026 Free Software Foundation, Inc.
> +
> + 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
> + <https://www.gnu.org/licenses/>. */
> +
> +# pragma GCC visibility push(hidden)
> +#include <assert.h>
> +#include <unistd.h>
> +#include <ldsodefs.h>
> +
> +#include <dl-machine.h>
> +#include <dl-debug.h>
> +
> +#define RESOLVE_MAP(map, scope, sym, version, flags) map
> +#include "elf/dynamic-link.h"
> +#include "elf/get-dynamic-info.h"
> +
> +/* Relocate static executable with PIE for local ifunc symbol. */
> +static void
> +init_cpu_features (void)
> +{
> + ElfW(Addr) file_p_vaddr = 0;
> + const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
> + size_t phnum = GL(dl_phnum);
> +
> + struct link_map *map = _dl_get_dl_main_map ();
> +
> + for (ph = phdr; ph < &phdr[phnum]; ++ph)
> + switch (ph->p_type)
> + {
> + case PT_LOAD:
> + /* Skip the empty PT_LOAD segment at offset 0. */
> + if (ph->p_filesz != 0 && ph->p_offset == 0)
> + file_p_vaddr = ph->p_vaddr;
> + break;
> + case PT_DYNAMIC:
> + map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
> + break;
> + default:
> + break;
> + }
> +
> + /* Figure out the run-time load address of static PIE. */
> + ElfW(Addr) l_addr = elf_machine_load_address ();
> + map->l_addr = l_addr - file_p_vaddr;
> +
> + map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
> +
> + elf_get_dynamic_info (map, false, true);
> +
> + if ((map)->l_info[DT_PLTGOT] != NULL && (map)->l_info[DT_PLTGOT]->d_un.d_ptr != 0)
> + {
> + ElfW(Rela) *reloc = (ElfW(Rela) *)(map->l_info[DT_JMPREL]->d_un.d_val + map->l_addr);
> + ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
> +
> + ElfW(Addr) * start = (ElfW(Addr) *)(gotplt + 2);
> + size_t rela_size = map->l_info[DT_PLTRELSZ]->d_un.d_val;
> + size_t num_plt_entries = rela_size / 8;
> +
> + ElfW(Addr) plt_addr = (ElfW(Addr))((ElfW(Addr) *)(*start) + 4) + (ElfW(Addr))map->l_addr;
> + for (int ranges_index = 0; ranges_index < num_plt_entries; ++ranges_index)
> + {
> + ElfW(Addr) r_info = reloc->r_info;
> + if(ELFW (R_TYPE) (r_info) == R_RISCV_IRELATIVE)
> + {
> + ElfW(Addr) addr = (ElfW(Addr))map->l_addr + reloc->r_addend;
> + *start = ((ElfW(Addr) (*) (uint64_t, void *, void *)) (addr))(0, NULL, NULL);
> + }
> +
> + start++;
> + reloc ++;
> + plt_addr += 16;
> + }
> + }
> +}
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index 8c7312ad98..dfb202157c 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -1,5 +1,5 @@
> /* Machine-dependent ELF dynamic relocation inline functions. RISC-V version.
> - Copyright (C) 2011-2026 Free Software Foundation, Inc.
> + Copyright (C) 2011-2025 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
> @@ -26,7 +26,7 @@
> #include <sys/asm.h>
> #include <dl-tls.h>
> #include <dl-irel.h>
> -#include <dl-static-tls.h>
> +#include <elf/dl-static-tls.h>
> #include <dl-machine-rel.h>
>
> #ifndef _RTLD_PROLOGUE
> diff --git a/sysdeps/riscv/libc-start.c b/sysdeps/riscv/libc-start.c
> new file mode 100644
> index 0000000000..5584ce165f
> --- /dev/null
> +++ b/sysdeps/riscv/libc-start.c
> @@ -0,0 +1,34 @@
> +/* Override csu/libc-start.c on riscv.
> + 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
> + <https://www.gnu.org/licenses/>. */
> +
> +# if ENABLE_STATIC_PIE
> +#ifndef SHARED
> +/* Relocate local IFUNC symbols in static PIE for early self relocation. */
> +# if BUILD_PIE_DEFAULT
> +# pragma GCC visibility push(hidden)
> +# endif
> +
> +# include <startup.h>
> +# include <ldsodefs.h>
> +# include <cpu-features.c>
> +
> +# define ARCH_INIT_CPU_FEATURES() init_cpu_features()
> +
> +#endif /* !SHARED */
> +#endif
> +#include <csu/libc-start.c>
More information about the Libc-alpha
mailing list