[RFC,v3] RISC-V: Fix SIGSEGV of --static-pie binaries on riscv64 [BZ #33911]
Checks
Commit Message
This patch fixes a SIGSEGV observed in --static-pie binaries on riscv64,
as reported in BZ #33911.
The first issue occurs when compiler optimizations are enabled: memory
initialization via `memset` may generate early libcalls before static PIE
relocation, leading to incorrect symbol resolution.
The second issue occurs when compiler optimizations are not enabled:
`memcpy` may be emitted as a direct libc call instead of an inlined
instruction sequence, which can also trigger relocation problems.
This patch addresses both issues by providing safe early implementations
that avoid generating libcalls before static PIE relocation, ensuring
memory operations are performed correctly.
Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
---
elf/dynamic-link.h | 67 ++++++++++++++++++++++++++------------
sysdeps/riscv/dl-machine.h | 15 ++++++---
2 files changed, 57 insertions(+), 25 deletions(-)
Comments
On Sat, Mar 7, 2026 at 10:22 PM daichengrong <daichengrong@iscas.ac.cn> wrote:
>
> This patch fixes a SIGSEGV observed in --static-pie binaries on riscv64,
> as reported in BZ #33911.
>
> The first issue occurs when compiler optimizations are enabled: memory
> initialization via `memset` may generate early libcalls before static PIE
> relocation, leading to incorrect symbol resolution.
>
> The second issue occurs when compiler optimizations are not enabled:
> `memcpy` may be emitted as a direct libc call instead of an inlined
> instruction sequence, which can also trigger relocation problems.
>
> This patch addresses both issues by providing safe early implementations
> that avoid generating libcalls before static PIE relocation, ensuring
> memory operations are performed correctly.
Can you update
riscv/multiarch/dl-symbol-redir-ifunc.h
instead?
> Em 8 de mar. de 2026, à(s) 03:22, daichengrong <daichengrong@iscas.ac.cn> escreveu:
>
> This patch fixes a SIGSEGV observed in --static-pie binaries on riscv64,
> as reported in BZ #33911.
>
> The first issue occurs when compiler optimizations are enabled: memory
> initialization via `memset` may generate early libcalls before static PIE
> relocation, leading to incorrect symbol resolution.
>
> The second issue occurs when compiler optimizations are not enabled:
> `memcpy` may be emitted as a direct libc call instead of an inlined
> instruction sequence, which can also trigger relocation problems.
>
> This patch addresses both issues by providing safe early implementations
> that avoid generating libcalls before static PIE relocation, ensuring
> memory operations are performed correctly.
>
> Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
> ---
> elf/dynamic-link.h | 67 ++++++++++++++++++++++++++------------
> sysdeps/riscv/dl-machine.h | 15 ++++++---
> 2 files changed, 57 insertions(+), 25 deletions(-)
>
> diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
> index a46f36b8d4..8c12812b63 100644
> --- a/elf/dynamic-link.h
> +++ b/elf/dynamic-link.h
> @@ -18,7 +18,14 @@
>
> #include <dl-machine.h>
> #include <elf.h>
> +// #include <sys/cdefs.h>
> +#ifndef unlikely
> +#define unlikely(x) __builtin_expect(!!(x), 0)
> +#endif
>
> +#ifndef likely
> +#define likely(x) __builtin_expect(!!(x), 1)
> +#endif
> #ifdef RESOLVE_MAP
> /* We pass reloc_addr as a pointer to void, as opposed to a pointer to
> ElfW(Addr), because not all architectures can assume that the
> @@ -82,11 +89,11 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
> do { \
> struct { ElfW(Addr) start, size; \
> __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
> - ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
> + ranges[2]; \
> \
> /* With DT_RELR, DT_RELA/DT_REL can have zero value. */ \
> - if ((map)->l_info[DT_##RELOC] != NULL \
> - && (map)->l_info[DT_##RELOC]->d_un.d_ptr != 0) \
> + if (likely((map)->l_info[DT_##RELOC] != NULL \
> + && (map)->l_info[DT_##RELOC]->d_un.d_ptr != 0)) \
> { \
> ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
> ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
> @@ -94,28 +101,46 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
> ranges[0].nrelative \
> = map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val; \
> } \
> - if ((map)->l_info[DT_PLTREL] \
> - && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
> + else \
> + { \
> + ranges[0].size = 0; \
> + ranges[0].nrelative = 0; \
> + } \
> + if (likely((map)->l_info[DT_PLTREL] \
> + && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC))) \
> { \
> ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
> ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
> \
> - if (ranges[0].start == 0) \
> - ranges[0].start = start; \
> - if (ranges[0].start + ranges[0].size == (start + size)) \
> - ranges[0].size -= size; \
> - if (!(do_lazy) \
> - && (ranges[0].start + ranges[0].size) == start) \
> - { \
> - /* Combine processing the sections. */ \
> - ranges[0].size += size; \
> - } \
> - else \
> - { \
> - ranges[1].start = start; \
> - ranges[1].size = size; \
> - ranges[1].lazy = (do_lazy); \
> - } \
> + if (ranges[0].size == 0) \
> + { \
> + ranges[0].lazy = (do_lazy); \
> + ranges[0].start = start; \
> + ranges[0].size = size; \
> + ranges[1].size = 0; \
> + } \
> + else \
> + { \
> + ranges[1].start = start; \
> + ranges[1].size = size; \
> + ranges[1].lazy = (do_lazy); \
> + if (likely(do_lazy)) \
> + { \
> + /* Combine processing the sections. */ \
> + if (unlikely(ranges[0].start + ranges[0].size == (start + size))) \
> + { \
> + ranges[1].size = 0; \
> + ranges[0].start = ranges[0].start; \
> + ranges[1].lazy = 0; \
> + ranges[0].size = ranges[0].size + size; \
> + ranges[0].lazy = (do_lazy); \
> + } \
> + } \
> + } \
> + } \
> + else \
> + { \
> + ranges[1].size = 0; \
> } \
> \
> for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index 8c7312ad98..0c6b55c3f3 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -157,10 +157,17 @@ __attribute__ ((always_inline))
> elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
> void *const reloc_addr)
> {
> - /* R_RISCV_RELATIVE might located in debug info section which might not
> - aligned to XLEN bytes. Also support relocations on unaligned offsets. */
> - ElfW(Addr) value = l_addr + reloc->r_addend;
> - memcpy (reloc_addr, &value, sizeof value);
> +#if __riscv_xlen == 64
> + uint64_t value = l_addr + reloc->r_addend;
> +
> + uint32_t lo = (uint32_t)value;
> + uint32_t hi = (uint32_t)(value >> 32);
> +
> + ((uint32_t*)reloc_addr)[0] = lo;
> + ((uint32_t*)reloc_addr)[1] = hi;
> +#else
> + *reloc_addr = l_addr + reloc->r_addend;
> +#endif
> }
>
> /* Perform a relocation described by R_INFO at the location pointed to
> --
> 2.25.1
>
Did you check if my proposed solution does work [1]?
It is polite to at least comment why you think it is not the right solution and why you need a different solution instead.
[1] https://sourceware.org/pipermail/libc-alpha/2026-March/175705.html
On 3/9/26 00:38, Adhemerval Zanella wrote:
> Did you check if my proposed solution does work [1]?
>
> It is polite to at least comment why you think it is not the right solution and why you need a different solution instead.
>
> [1] https://sourceware.org/pipermail/libc-alpha/2026-March/175705.html
Hi Adhemerval,
Thanks for your v2 review and the proposed solution.
I have read your suggestion and understand the rationale. I do have some reservations about it, but I thought it would be premature to propose my own idea without testing it first. So in v3 RFC, I implemented a reference version and did some preliminary validation. My goal was to explore the feasibility through an actual implementation, though I realize it may not be fully mature yet.
I should have replied under the v2 thread when posting v3 RFC to explain my reasoning, but it was delayed—apologies. I will very soon post a comment under your v2 reply with more detailed explanation.
I’ll also test your proposed solution and compare it with my current implementation to see which approach works better. Happy to continue discussing improvements.
On 3/8/26 23:48, H.J. Lu wrote:
>
> Can you update
>
> riscv/multiarch/dl-symbol-redir-ifunc.h
>
> instead?
>
>
The RFC v3 implementation is primarily intended as a reference experiment
to explore the idea of avoiding libcalls in ELF early relocation paths.
It helps us better understand and evaluate possible optimization approaches.
On Mär 08 2026, daichengrong wrote:
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index 8c7312ad98..0c6b55c3f3 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -157,10 +157,17 @@ __attribute__ ((always_inline))
> elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
> void *const reloc_addr)
> {
> - /* R_RISCV_RELATIVE might located in debug info section which might not
> - aligned to XLEN bytes. Also support relocations on unaligned offsets. */
> - ElfW(Addr) value = l_addr + reloc->r_addend;
> - memcpy (reloc_addr, &value, sizeof value);
> +#if __riscv_xlen == 64
> + uint64_t value = l_addr + reloc->r_addend;
> +
> + uint32_t lo = (uint32_t)value;
> + uint32_t hi = (uint32_t)(value >> 32);
> +
> + ((uint32_t*)reloc_addr)[0] = lo;
> + ((uint32_t*)reloc_addr)[1] = hi;
Why do you need to split the store?
@@ -18,7 +18,14 @@
#include <dl-machine.h>
#include <elf.h>
+// #include <sys/cdefs.h>
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
#ifdef RESOLVE_MAP
/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
ElfW(Addr), because not all architectures can assume that the
@@ -82,11 +89,11 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
do { \
struct { ElfW(Addr) start, size; \
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
- ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
+ ranges[2]; \
\
/* With DT_RELR, DT_RELA/DT_REL can have zero value. */ \
- if ((map)->l_info[DT_##RELOC] != NULL \
- && (map)->l_info[DT_##RELOC]->d_un.d_ptr != 0) \
+ if (likely((map)->l_info[DT_##RELOC] != NULL \
+ && (map)->l_info[DT_##RELOC]->d_un.d_ptr != 0)) \
{ \
ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
@@ -94,28 +101,46 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
ranges[0].nrelative \
= map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val; \
} \
- if ((map)->l_info[DT_PLTREL] \
- && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
+ else \
+ { \
+ ranges[0].size = 0; \
+ ranges[0].nrelative = 0; \
+ } \
+ if (likely((map)->l_info[DT_PLTREL] \
+ && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC))) \
{ \
ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
\
- if (ranges[0].start == 0) \
- ranges[0].start = start; \
- if (ranges[0].start + ranges[0].size == (start + size)) \
- ranges[0].size -= size; \
- if (!(do_lazy) \
- && (ranges[0].start + ranges[0].size) == start) \
- { \
- /* Combine processing the sections. */ \
- ranges[0].size += size; \
- } \
- else \
- { \
- ranges[1].start = start; \
- ranges[1].size = size; \
- ranges[1].lazy = (do_lazy); \
- } \
+ if (ranges[0].size == 0) \
+ { \
+ ranges[0].lazy = (do_lazy); \
+ ranges[0].start = start; \
+ ranges[0].size = size; \
+ ranges[1].size = 0; \
+ } \
+ else \
+ { \
+ ranges[1].start = start; \
+ ranges[1].size = size; \
+ ranges[1].lazy = (do_lazy); \
+ if (likely(do_lazy)) \
+ { \
+ /* Combine processing the sections. */ \
+ if (unlikely(ranges[0].start + ranges[0].size == (start + size))) \
+ { \
+ ranges[1].size = 0; \
+ ranges[0].start = ranges[0].start; \
+ ranges[1].lazy = 0; \
+ ranges[0].size = ranges[0].size + size; \
+ ranges[0].lazy = (do_lazy); \
+ } \
+ } \
+ } \
+ } \
+ else \
+ { \
+ ranges[1].size = 0; \
} \
\
for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
@@ -157,10 +157,17 @@ __attribute__ ((always_inline))
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
void *const reloc_addr)
{
- /* R_RISCV_RELATIVE might located in debug info section which might not
- aligned to XLEN bytes. Also support relocations on unaligned offsets. */
- ElfW(Addr) value = l_addr + reloc->r_addend;
- memcpy (reloc_addr, &value, sizeof value);
+#if __riscv_xlen == 64
+ uint64_t value = l_addr + reloc->r_addend;
+
+ uint32_t lo = (uint32_t)value;
+ uint32_t hi = (uint32_t)(value >> 32);
+
+ ((uint32_t*)reloc_addr)[0] = lo;
+ ((uint32_t*)reloc_addr)[1] = hi;
+#else
+ *reloc_addr = l_addr + reloc->r_addend;
+#endif
}
/* Perform a relocation described by R_INFO at the location pointed to