diff mbox series

[v3] RISC-V: Enable static-pie.

Message ID 20240102105415.516313-1-yanzhang.wang@intel.com
State New
Headers show
Series [v3] RISC-V: Enable static-pie. | expand

Commit Message

Wang, Yanzhang Jan. 2, 2024, 10:54 a.m. UTC
From: Yanzhang Wang <yanzhang.wang@intel.com>

This patch referents the commit 374cef3 to add static-pie support. And
because the dummy link map is used when relocating ourselves, so need
not to set __global_pointer$ at this time.

It will also check whether toolchain supports to build static-pie.
---
 sysdeps/riscv/configure    | 49 ++++++++++++++++++++++++++++++++++++++
 sysdeps/riscv/configure.ac | 27 +++++++++++++++++++++
 sysdeps/riscv/dl-machine.h |  2 +-
 3 files changed, 77 insertions(+), 1 deletion(-)

Comments

Adhemerval Zanella Netto Jan. 2, 2024, 6:30 p.m. UTC | #1
On 02/01/24 07:54, yanzhang.wang@intel.com wrote:
> From: Yanzhang Wang <yanzhang.wang@intel.com>
> 
> This patch referents the commit 374cef3 to add static-pie support. And
> because the dummy link map is used when relocating ourselves, so need
> not to set __global_pointer$ at this time.
> 
> It will also check whether toolchain supports to build static-pie.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  sysdeps/riscv/configure    | 49 ++++++++++++++++++++++++++++++++++++++
>  sysdeps/riscv/configure.ac | 27 +++++++++++++++++++++
>  sysdeps/riscv/dl-machine.h |  2 +-
>  3 files changed, 77 insertions(+), 1 deletion(-)
> 
> diff --git a/sysdeps/riscv/configure b/sysdeps/riscv/configure
> index acd1f5e743..c8f01709f8 100644
> --- a/sysdeps/riscv/configure
> +++ b/sysdeps/riscv/configure
> @@ -31,3 +31,52 @@ printf "%s\n" "$libc_cv_riscv_r_align" >&6; }
>  config_vars="$config_vars
>  riscv-r-align = $libc_cv_riscv_r_align"
>  
> +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the toolchain is sufficient to build static PIE on RISC-V" >&5
> +printf %s "checking if the toolchain is sufficient to build static PIE on RISC-V... " >&6; }
> +if test ${libc_cv_static_pie_on_riscv+y}
> +then :
> +  printf %s "(cached) " >&6
> +else $as_nop
> +
> +  cat > conftest1.S <<\EOF
> +    .globl _start
> +    .type   _start, @function
> +_start:
> +    nop
> +
> +    .data
> +    /* This should produce an R_RISCV_RELATIVE in the static PIE.  */
> +    .dword      _start
> +EOF
> +
> +  libc_cv_static_pie_on_riscv=no
> +  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest1 conftest1.S'
> +  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> +  (eval $ac_try) 2>&5
> +  ac_status=$?
> +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; } \
> +     && { ac_try='LC_ALL=C $READELF -Wr conftest1 | grep -q R_RISCV_RELATIVE'
> +  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> +  (eval $ac_try) 2>&5
> +  ac_status=$?
> +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; } \
> +     && ! { ac_try='LC_ALL=C $READELF -Wl conftest1 | grep -q INTERP'
> +  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> +  (eval $ac_try) 2>&5
> +  ac_status=$?
> +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; }
> +  then
> +    libc_cv_static_pie_on_riscv=yes
> +  fi
> +  rm -rf conftest*
> +fi
> +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_static_pie_on_riscv" >&5
> +printf "%s\n" "$libc_cv_static_pie_on_riscv" >&6; }
> +
> +if test "$libc_cv_static_pie_on_riscv" = yes; then
> +  printf "%s\n" "#define SUPPORT_STATIC_PIE 1" >>confdefs.h
> +
> +fi
> diff --git a/sysdeps/riscv/configure.ac b/sysdeps/riscv/configure.ac
> index dbcc216689..ee3d1ed014 100644
> --- a/sysdeps/riscv/configure.ac
> +++ b/sysdeps/riscv/configure.ac
> @@ -16,3 +16,30 @@ EOF
>    fi
>    rm -rf conftest.*])
>  LIBC_CONFIG_VAR([riscv-r-align], [$libc_cv_riscv_r_align])
> +
> +dnl Test if the toolchain is new enough for static PIE.
> +AC_CACHE_CHECK([if the toolchain is sufficient to build static PIE on RISC-V],
> +libc_cv_static_pie_on_riscv, [
> +  cat > conftest1.S <<\EOF
> +    .globl _start
> +    .type   _start, @function
> +_start:
> +    nop
> +
> +    .data
> +    /* This should produce an R_RISCV_RELATIVE in the static PIE.  */
> +    .dword      _start
> +EOF
> +
> +  libc_cv_static_pie_on_riscv=no
> +  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest1 conftest1.S]) \
> +     && AC_TRY_COMMAND([LC_ALL=C $READELF -Wr conftest1 | grep -q R_RISCV_RELATIVE]) \
> +     && ! AC_TRY_COMMAND([LC_ALL=C $READELF -Wl conftest1 | grep -q INTERP])
> +  then
> +    libc_cv_static_pie_on_riscv=yes
> +  fi
> +  rm -rf conftest* ])
> +
> +if test "$libc_cv_static_pie_on_riscv" = yes; then
> +  AC_DEFINE(SUPPORT_STATIC_PIE)
> +fi
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index ffb8c4aaa0..0cbb476c05 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -348,7 +348,7 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
>        gotplt[1] = (ElfW(Addr)) l;
>      }
>  
> -  if (l->l_type == lt_executable)
> +  if (l->l_type == lt_executable && l->l_scope != NULL)
>      {
>        /* The __global_pointer$ may not be defined by the linker if the
>  	 $gp register does not be used to access the global variable
Andreas Schwab Jan. 17, 2024, 12:23 p.m. UTC | #2
On Jan 02 2024, yanzhang.wang@intel.com wrote:

> From: Yanzhang Wang <yanzhang.wang@intel.com>
>
> This patch referents the commit 374cef3 to add static-pie support. And
> because the dummy link map is used when relocating ourselves, so need
> not to set __global_pointer$ at this time.
>
> It will also check whether toolchain supports to build static-pie.

How did you check that?  It doesn't work here:

Breakpoint 1, _start () at ../sysdeps/riscv/start.S:50
50              call  load_gp
1: x/i $pc
=> 0x3ff7f59ea4 <_start>:       jal     0x3ff7f59ec6 <load_gp>
(gdb) ni
_start () at ../sysdeps/riscv/start.S:74
74              lla   gp, __global_pointer$
1: x/i $pc
=> 0x3ff7f59ec6 <load_gp>:      auipc   gp,0xa0
(gdb) 
0x0000003ff7f59eca      74              lla   gp, __global_pointer$
1: x/i $pc
=> 0x3ff7f59eca <_start+38>:    add     gp,gp,706
(gdb) 
load_gp () at ../sysdeps/riscv/start.S:76
76              ret
1: x/i $pc
=> 0x3ff7f59ece <load_gp+8>:    ret
(gdb) 
_start () at ../sysdeps/riscv/start.S:51
51              mv    a5, a0  /* rtld_fini.  */
1: x/i $pc
=> 0x3ff7f59ea8 <_start+4>:     mv      a5,a0
(gdb) 
53              la   a0, main
1: x/i $pc
=> 0x3ff7f59eaa <_start+6>:     auipc   a0,0x9e
(gdb) 
0x0000003ff7f59eae      53              la   a0, main
1: x/i $pc
=> 0x3ff7f59eae <_start+10>:    ld      a0,-74(a0)
(gdb) 
54              REG_L a1, 0(sp)      /* argc.  */
1: x/i $pc
=> 0x3ff7f59eb2 <_start+14>:    ld      a1,0(sp)
(gdb) i reg a0
a0             0x0      0
Andreas Schwab Jan. 29, 2024, 12:46 p.m. UTC | #3
On Jan 02 2024, yanzhang.wang@intel.com wrote:

> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index ffb8c4aaa0..0cbb476c05 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -348,7 +348,7 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
>        gotplt[1] = (ElfW(Addr)) l;
>      }
>  
> -  if (l->l_type == lt_executable)
> +  if (l->l_type == lt_executable && l->l_scope != NULL)

This is not the right way to test for static PIE, it tries to access a
non-relocated non-zero pointer.  The mold linker, when producing
relative relocations, puts the addend both in the relocation addend and
the relocated field, which is perfectly valid to do, so this is non-zero
here.
Wang, Yanzhang Feb. 1, 2024, 12:39 p.m. UTC | #4
Hi Andreas,

Sorry for the late response. Thanks your comments! And I don't quite
follow your comments. Could you please give some further information?

> (gdb) ni
> _start () at ../sysdeps/riscv/start.S:74
> 74              lla   gp, __global_pointer$
> 1: x/i $pc
> => 0x3ff7f59ec6 <load_gp>:      auipc   gp,0xa0
> (gdb)
> 0x0000003ff7f59eca      74              lla   gp, __global_pointer$
> 1: x/i $pc
> => 0x3ff7f59eca <_start+38>:    add     gp,gp,706
> (gdb)
> load_gp () at ../sysdeps/riscv/start.S:76
> 76              ret
> 1: x/i $pc
> => 0x3ff7f59ece <load_gp+8>:    ret
> (gdb)
> _start () at ../sysdeps/riscv/start.S:51
> 51              mv    a5, a0  /* rtld_fini.  */
> 1: x/i $pc
> => 0x3ff7f59ea8 <_start+4>:     mv      a5,a0
> (gdb)
> 53              la   a0, main
> 1: x/i $pc
> => 0x3ff7f59eaa <_start+6>:     auipc   a0,0x9e
> (gdb)
> 0x0000003ff7f59eae      53              la   a0, main
> 1: x/i $pc
> => 0x3ff7f59eae <_start+10>:    ld      a0,-74(a0)
> (gdb)
> 54              REG_L a1, 0(sp)      /* argc.  */
> 1: x/i $pc
> => 0x3ff7f59eb2 <_start+14>:    ld      a1,0(sp)
> (gdb) i reg a0
> a0             0x0      0

The first, it seems you have constructed a test case which should fail
this patch. But based on your gdb comment, I'm not sure which step is
not correct. Should the a0 register be non-zero or the gp register be
wrong? 

---

The code in the if will try to lookup the __global_pointer$ and move to the
gp register. It will be failed because l->l_scope is NULL when static-pie.
So I added this checking to avoid this failure.

> > +  if (l->l_type == lt_executable && l->l_scope != NULL)


> This is not the right way to test for static PIE, it tries to access a
> non-relocated non-zero pointer.  The mold linker, when producing relative
> relocations, puts the addend both in the relocation addend and the
> relocated field, which is perfectly valid to do, so this is non-zero here.

The second, do you mean there's a case that l->l_scope is not NULL when built
with static-pie? Or we should not access the members in link_map ?

Thanks,
Yanzhang

> -----Original Message-----
> From: Andreas Schwab <schwab@suse.de>
> Sent: Monday, January 29, 2024 8:46 PM
> To: Wang, Yanzhang <yanzhang.wang@intel.com>
> Cc: libc-alpha@sourceware.org; adhemerval.zanella@linaro.org
> Subject: Re: [PATCH v3] RISC-V: Enable static-pie.
> 
> On Jan 02 2024, yanzhang.wang@intel.com wrote:
> 
> > diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> > index ffb8c4aaa0..0cbb476c05 100644
> > --- a/sysdeps/riscv/dl-machine.h
> > +++ b/sysdeps/riscv/dl-machine.h
> > @@ -348,7 +348,7 @@ elf_machine_runtime_setup (struct link_map *l,
> struct r_scope_elem *scope[],
> >        gotplt[1] = (ElfW(Addr)) l;
> >      }
> >
> > -  if (l->l_type == lt_executable)
> > +  if (l->l_type == lt_executable && l->l_scope != NULL)
> 
> This is not the right way to test for static PIE, it tries to access a
> non-relocated non-zero pointer.  The mold linker, when producing relative
> relocations, puts the addend both in the relocation addend and the
> relocated field, which is perfectly valid to do, so this is non-zero here.
> 
> --
> Andreas Schwab, SUSE Labs, schwab@suse.de GPG Key fingerprint = 0196 BAD8
> 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7 "And now for something
> completely different."
Andreas Schwab Feb. 1, 2024, 12:53 p.m. UTC | #5
On Feb 01 2024, Wang, Yanzhang wrote:

> The code in the if will try to lookup the __global_pointer$ and move to the
> gp register. It will be failed because l->l_scope is NULL when static-pie.

No, l->l_scope is an unrelocated pointer.  Since ld.mold puts the addend
also in the relocated field, it is read as a nonzero, but invalid
pointer.  See the static-pie tests in the mold testsuite.
Maciej W. Rozycki May 21, 2024, 11:13 a.m. UTC | #6
On Tue, 2 Jan 2024, yanzhang.wang@intel.com wrote:

> This patch referents the commit 374cef3 to add static-pie support. And
> because the dummy link map is used when relocating ourselves, so need
> not to set __global_pointer$ at this time.
> 
> It will also check whether toolchain supports to build static-pie.

 Somehow the check fails to trigger here, causing a build error:

riscv64-linux-gnu-gcc  -o .../support/test-run-command -nostdlib -nostartfiles -static -static-pie     .../csu/rcrt1.o .../csu/crti.o `riscv64-linux-gnu-gcc   --print-file-name=crtbeginS.o` .../support/test-run-command.o .../elf/static-stubs.o .../support/libsupport_nonshared.a  -Wl,--start-group .../libc.a -lgcc  -Wl,--end-group `riscv64-linux-gnu-gcc   --print-file-name=crtendS.o` .../csu/crtn.o.../bin/../lib/gcc/riscv64-linux-gnu/14.0.0/../../../../riscv64-linux-gnu/bin/ld: read-only segment has dynamic relocations
collect2: error: ld returned 1 exit status
make[2]: *** [../Rules:290: .../support/test-run-command] Error 1

I have filed BZ #31773.

  Maciej
diff mbox series

Patch

diff --git a/sysdeps/riscv/configure b/sysdeps/riscv/configure
index acd1f5e743..c8f01709f8 100644
--- a/sysdeps/riscv/configure
+++ b/sysdeps/riscv/configure
@@ -31,3 +31,52 @@  printf "%s\n" "$libc_cv_riscv_r_align" >&6; }
 config_vars="$config_vars
 riscv-r-align = $libc_cv_riscv_r_align"
 
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the toolchain is sufficient to build static PIE on RISC-V" >&5
+printf %s "checking if the toolchain is sufficient to build static PIE on RISC-V... " >&6; }
+if test ${libc_cv_static_pie_on_riscv+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+
+  cat > conftest1.S <<\EOF
+    .globl _start
+    .type   _start, @function
+_start:
+    nop
+
+    .data
+    /* This should produce an R_RISCV_RELATIVE in the static PIE.  */
+    .dword      _start
+EOF
+
+  libc_cv_static_pie_on_riscv=no
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest1 conftest1.S'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } \
+     && { ac_try='LC_ALL=C $READELF -Wr conftest1 | grep -q R_RISCV_RELATIVE'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } \
+     && ! { ac_try='LC_ALL=C $READELF -Wl conftest1 | grep -q INTERP'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+  then
+    libc_cv_static_pie_on_riscv=yes
+  fi
+  rm -rf conftest*
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_static_pie_on_riscv" >&5
+printf "%s\n" "$libc_cv_static_pie_on_riscv" >&6; }
+
+if test "$libc_cv_static_pie_on_riscv" = yes; then
+  printf "%s\n" "#define SUPPORT_STATIC_PIE 1" >>confdefs.h
+
+fi
diff --git a/sysdeps/riscv/configure.ac b/sysdeps/riscv/configure.ac
index dbcc216689..ee3d1ed014 100644
--- a/sysdeps/riscv/configure.ac
+++ b/sysdeps/riscv/configure.ac
@@ -16,3 +16,30 @@  EOF
   fi
   rm -rf conftest.*])
 LIBC_CONFIG_VAR([riscv-r-align], [$libc_cv_riscv_r_align])
+
+dnl Test if the toolchain is new enough for static PIE.
+AC_CACHE_CHECK([if the toolchain is sufficient to build static PIE on RISC-V],
+libc_cv_static_pie_on_riscv, [
+  cat > conftest1.S <<\EOF
+    .globl _start
+    .type   _start, @function
+_start:
+    nop
+
+    .data
+    /* This should produce an R_RISCV_RELATIVE in the static PIE.  */
+    .dword      _start
+EOF
+
+  libc_cv_static_pie_on_riscv=no
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest1 conftest1.S]) \
+     && AC_TRY_COMMAND([LC_ALL=C $READELF -Wr conftest1 | grep -q R_RISCV_RELATIVE]) \
+     && ! AC_TRY_COMMAND([LC_ALL=C $READELF -Wl conftest1 | grep -q INTERP])
+  then
+    libc_cv_static_pie_on_riscv=yes
+  fi
+  rm -rf conftest* ])
+
+if test "$libc_cv_static_pie_on_riscv" = yes; then
+  AC_DEFINE(SUPPORT_STATIC_PIE)
+fi
diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
index ffb8c4aaa0..0cbb476c05 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -348,7 +348,7 @@  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
       gotplt[1] = (ElfW(Addr)) l;
     }
 
-  if (l->l_type == lt_executable)
+  if (l->l_type == lt_executable && l->l_scope != NULL)
     {
       /* The __global_pointer$ may not be defined by the linker if the
 	 $gp register does not be used to access the global variable