diff mbox series

[v3,1/1] LoongArch: Add static PIE support

Message ID 20220924074534.1566173-2-xry111@xry111.site
State New
Headers show
Series LoongArch: Add static PIE support | expand

Commit Message

Xi Ruoyao Sept. 24, 2022, 7:45 a.m. UTC
If the compiler is new enough, enable static PIE support.  In the static
PIE version of _start (in rcrt1.o), use la.pcrel instead of la.got
because in a static PIE we cannot use GOT entries until the dynamic
relocations for GOT are resolved.
---
 sysdeps/loongarch/configure    | 48 ++++++++++++++++++++++++++++++++++
 sysdeps/loongarch/configure.ac | 36 +++++++++++++++++++++++++
 sysdeps/loongarch/start.S      | 14 +++++++---
 3 files changed, 95 insertions(+), 3 deletions(-)

Comments

caiyinyu Sept. 29, 2022, 1:32 p.m. UTC | #1
在 2022/9/24 下午3:45, Xi Ruoyao 写道:
> If the compiler is new enough, enable static PIE support.  In the static
> PIE version of _start (in rcrt1.o), use la.pcrel instead of la.got
> because in a static PIE we cannot use GOT entries until the dynamic
> relocations for GOT are resolved.
> ---
>   sysdeps/loongarch/configure    | 48 ++++++++++++++++++++++++++++++++++
>   sysdeps/loongarch/configure.ac | 36 +++++++++++++++++++++++++
>   sysdeps/loongarch/start.S      | 14 +++++++---
>   3 files changed, 95 insertions(+), 3 deletions(-)
>
> diff --git a/sysdeps/loongarch/configure b/sysdeps/loongarch/configure
> index 43b54d4965..70d6fec5c1 100644
> --- a/sysdeps/loongarch/configure
> +++ b/sysdeps/loongarch/configure
> @@ -3,3 +3,51 @@
>   
>   $as_echo "#define HIDDEN_VAR_NEEDS_DYNAMIC_RELOC 1" >>confdefs.h
>   
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the toolchain is sufficient to build static PIE on LoongArch" >&5
> +$as_echo_n "checking if the toolchain is sufficient to build static PIE on LoongArch... " >&6; }
> +if ${libc_cv_static_pie_on_loongarch+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +
> +  cat > conftest.S << EOF
> +.global _start
> +.type _start, @function
> +_start:
> +  li.w $a7, 93
> +  /* This ensures the assembler supports explicit reloc.  */
> +  pcalau12i $a0, %pc_hi20(x)
> +  ld.w $a0, $a0, %pc_lo12(x)
> +  syscall 0
> +
> +.data
> +x:
> +  .word 0
> +  /* This should produce an R_LARCH_RELATIVE in the static PIE.  */
> +  .dword _start
> +EOF
> +  libc_cv_static_pie_on_loongarch=no
> +  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest conftest.S'
> +  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> +  (eval $ac_try) 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; } \
> +     && { ac_try='LC_ALL=C $READELF -Wr conftest | grep -q R_LARCH_RELATIVE'
> +  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> +  (eval $ac_try) 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; }
> +  then
> +    libc_cv_static_pie_on_loongarch=yes
> +  fi
> +  rm -rf conftest.*
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_static_pie_on_loongarch" >&5
> +$as_echo "$libc_cv_static_pie_on_loongarch" >&6; }
> +
> +if test "$libc_cv_static_pie_on_loongarch" = yes; then
> +  $as_echo "#define SUPPORT_STATIC_PIE 1" >>confdefs.h
> +
> +fi
> diff --git a/sysdeps/loongarch/configure.ac b/sysdeps/loongarch/configure.ac
> index f744367bf3..282b95b0fb 100644
> --- a/sysdeps/loongarch/configure.ac
> +++ b/sysdeps/loongarch/configure.ac
> @@ -4,3 +4,39 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
>   dnl It is always possible to access static and hidden symbols in an
>   dnl position independent way.
>   AC_DEFINE(HIDDEN_VAR_NEEDS_DYNAMIC_RELOC)
> +
> +dnl Test if the toolchain is new enough for static PIE.
> +dnl We need a GAS supporting explicit reloc (older GAS produces stack-based
> +dnl reloc and triggers an internal error in the linker).  And, we need GCC to
> +dnl pass the correct linker flags for static PIE.  GCC >= 13 and GAS >= 2.40
> +dnl satisify the requirement, but a distro may backport static PIE support into
> +dnl earlier GCC or Binutils releases as well.
> +AC_CACHE_CHECK([if the toolchain is sufficient to build static PIE on LoongArch],
> +libc_cv_static_pie_on_loongarch, [
> +  cat > conftest.S << EOF
> +.global _start
> +.type _start, @function
> +_start:
> +  li.w $a7, 93
> +  /* This ensures the assembler supports explicit reloc.  */
> +  pcalau12i $a0, %pc_hi20(x)
> +  ld.w $a0, $a0, %pc_lo12(x)
> +  syscall 0
> +
> +.data
> +x:
> +  .word 0


Tested on LoongArch machine with latest gcc and binutils (master):

gcc 13 fa4bc21bac70df5ae5712a1933a2e6bb5bf8d42b

binutils 2.39 4f56cf059ca883ca86c8f15cfc8a3e27465bf4b0

linux kernel 5.19

All passed.

Here are some mistakes:

diff --git a/sysdeps/loongarch/configure b/sysdeps/loongarch/configure
index 70d6fec5c1..6edd6d08a5 100644
--- a/sysdeps/loongarch/configure
+++ b/sysdeps/loongarch/configure
@@ -14,10 +14,10 @@ else
  .global _start
  .type _start, @function
  _start:
-  li.w $a7, 93
+  li.w \$a7, 93
    /* This ensures the assembler supports explicit reloc.  */
-  pcalau12i $a0, %pc_hi20(x)
-  ld.w $a0, $a0, %pc_lo12(x)
+  pcalau12i \$a0, %pc_hi20(x)
+  ld.w \$a0, \$a0, %pc_lo12(x)
    syscall 0

  .data
diff --git a/sysdeps/loongarch/configure.ac b/sysdeps/loongarch/configure.ac
index 282b95b0fb..a8a373bea3 100644
--- a/sysdeps/loongarch/configure.ac
+++ b/sysdeps/loongarch/configure.ac
@@ -17,10 +17,10 @@ libc_cv_static_pie_on_loongarch, [
  .global _start
  .type _start, @function
  _start:
-  li.w $a7, 93
+  li.w \$a7, 93
    /* This ensures the assembler supports explicit reloc.  */
-  pcalau12i $a0, %pc_hi20(x)
-  ld.w $a0, $a0, %pc_lo12(x)
+  pcalau12i \$a0, %pc_hi20(x)
+  ld.w \$a0, \$a0, %pc_lo12(x)
    syscall 0

  .data



> +  /* This should produce an R_LARCH_RELATIVE in the static PIE.  */
> +  .dword _start
> +EOF
> +  libc_cv_static_pie_on_loongarch=no
> +  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest conftest.S]) \
> +     && AC_TRY_COMMAND([LC_ALL=C $READELF -Wr conftest | grep -q R_LARCH_RELATIVE])
> +  then
> +    libc_cv_static_pie_on_loongarch=yes
> +  fi
> +  rm -rf conftest.*])
> +
> +if test "$libc_cv_static_pie_on_loongarch" = yes; then
> +  AC_DEFINE(SUPPORT_STATIC_PIE)
> +fi
> diff --git a/sysdeps/loongarch/start.S b/sysdeps/loongarch/start.S
> index e66af16d57..05cabd9b96 100644
> --- a/sysdeps/loongarch/start.S
> +++ b/sysdeps/loongarch/start.S
> @@ -60,9 +60,17 @@ ENTRY (ENTRY_POINT)
>   	cfi_undefined (1)
>   	or		a5, a0, zero /* rtld_fini */
>   
> +#if defined(PIC) && !defined(SHARED)
> +/* For static PIE, the GOT cannot be used in _start because the GOT entries are
> +   offsets instead of real addresses before __libc_start_main.  */
> +# define LA la.pcrel
> +#else
>   /* We must get symbol main through GOT table, since main may not be local.
>      For instance: googletest defines main in dynamic library.  */
> -	la.got		a0, t0, main
> +# define LA la.got
> +#endif
> +
> +	LA		a0, t0, main
>   	REG_L		a1, sp, 0
>   	ADDI		a2, sp, SZREG
>   
> @@ -73,9 +81,9 @@ ENTRY (ENTRY_POINT)
>   	move		a4, zero /* used to be fini */
>   	or		a6, sp, zero /* stack_end */
>   
> -	la.got		ra, t0, __libc_start_main
> +	LA		ra, t0, __libc_start_main
>   	jirl		ra, ra, 0
>   
> -	la.got		ra, t0, abort
> +	LA		ra, t0, abort
>   	jirl		ra, ra, 0
>   END (ENTRY_POINT)
Xi Ruoyao Sept. 30, 2022, 12:47 p.m. UTC | #2
On Thu, 2022-09-29 at 21:32 +0800, caiyinyu wrote:
> Here are some mistakes:

Sorry for the stupid mistake...`

I need to be AFK for several days, will send v4 once I'm back.

> diff --git a/sysdeps/loongarch/configure b/sysdeps/loongarch/configure
> index 70d6fec5c1..6edd6d08a5 100644
> --- a/sysdeps/loongarch/configure
> +++ b/sysdeps/loongarch/configure
> @@ -14,10 +14,10 @@ else
>   .global _start
>   .type _start, @function
>   _start:
> -  li.w $a7, 93
> +  li.w \$a7, 93
>     /* This ensures the assembler supports explicit reloc.  */
> -  pcalau12i $a0, %pc_hi20(x)
> -  ld.w $a0, $a0, %pc_lo12(x)
> +  pcalau12i \$a0, %pc_hi20(x)
> +  ld.w \$a0, \$a0, %pc_lo12(x)
>     syscall 0
Adhemerval Zanella Netto Sept. 30, 2022, 12:54 p.m. UTC | #3
On 30/09/22 09:47, Xi Ruoyao via Libc-alpha wrote:
> On Thu, 2022-09-29 at 21:32 +0800, caiyinyu wrote:
>> Here are some mistakes:
> 
> Sorry for the stupid mistake...`
> 
> I need to be AFK for several days, will send v4 once I'm back.
> 
>> diff --git a/sysdeps/loongarch/configure b/sysdeps/loongarch/configure
>> index 70d6fec5c1..6edd6d08a5 100644
>> --- a/sysdeps/loongarch/configure
>> +++ b/sysdeps/loongarch/configure
>> @@ -14,10 +14,10 @@ else
>>   .global _start
>>   .type _start, @function
>>   _start:
>> -  li.w $a7, 93
>> +  li.w \$a7, 93
>>     /* This ensures the assembler supports explicit reloc.  */
>> -  pcalau12i $a0, %pc_hi20(x)
>> -  ld.w $a0, $a0, %pc_lo12(x)
>> +  pcalau12i \$a0, %pc_hi20(x)
>> +  ld.w \$a0, \$a0, %pc_lo12(x)
>>     syscall 0
> 


I was committed upstream nevertheless  (8b10727a9af3e2aa4b27dff0116bb8d3c9afce3d).
It upstream correct or does it require a the above fix?
Xi Ruoyao Sept. 30, 2022, 1:55 p.m. UTC | #4
On Fri, 2022-09-30 at 09:54 -0300, Adhemerval Zanella Netto wrote:
> 
> 
> On 30/09/22 09:47, Xi Ruoyao via Libc-alpha wrote:
> > On Thu, 2022-09-29 at 21:32 +0800, caiyinyu wrote:
> > > Here are some mistakes:
> > 
> > Sorry for the stupid mistake...`
> > 
> > I need to be AFK for several days, will send v4 once I'm back.
> > 
> > > diff --git a/sysdeps/loongarch/configure
> > > b/sysdeps/loongarch/configure
> > > index 70d6fec5c1..6edd6d08a5 100644
> > > --- a/sysdeps/loongarch/configure
> > > +++ b/sysdeps/loongarch/configure
> > > @@ -14,10 +14,10 @@ else
> > >   .global _start
> > >   .type _start, @function
> > >   _start:
> > > -  li.w $a7, 93
> > > +  li.w \$a7, 93
> > >     /* This ensures the assembler supports explicit reloc.  */
> > > -  pcalau12i $a0, %pc_hi20(x)
> > > -  ld.w $a0, $a0, %pc_lo12(x)
> > > +  pcalau12i \$a0, %pc_hi20(x)
> > > +  ld.w \$a0, \$a0, %pc_lo12(x)
> > >     syscall 0
> > 
> 
> 
> I was committed upstream nevertheless 
> (8b10727a9af3e2aa4b27dff0116bb8d3c9afce3d).
> It upstream correct or does it require a the above fix?

Upstream is correct.  Thanks!
Joseph Myers Sept. 30, 2022, 8:10 p.m. UTC | #5
It appears this has broken the build with binutils 2.39 branch, the 
default used by build-many-glibcs.py.  Either the configure test should be 
made stricter so it doesn't pass for binutils 2.39, or some relevant bug 
fix should be backported to binutils 2.39 branch.

Building the glibc testsuite, the error is:

collect2: fatal error: ld terminated with signal 11 [Segmentation fault], core dumped
compilation terminated.
../Rules:301: recipe for target '/scratch/jmyers/glibc-bot/build/glibcs/loongarch64-linux-gnu-lp64d/glibc/elf/ifuncmain1static' failed

But it also causes the second GCC build in the build-many-glibcs.py 
"compilers" build to fail, if such a build is run with glibc including 
this change.
Xi Ruoyao Oct. 1, 2022, 1:07 p.m. UTC | #6
On Fri, 2022-09-30 at 20:10 +0000, Joseph Myers wrote:
> It appears this has broken the build with binutils 2.39 branch, the 
> default used by build-many-glibcs.py.  Either the configure test should be 
> made stricter so it doesn't pass for binutils 2.39, or some relevant bug 
> fix should be backported to binutils 2.39 branch.
> 
> Building the glibc testsuite, the error is:
> 
> collect2: fatal error: ld terminated with signal 11 [Segmentation fault], core dumped
> compilation terminated.
> ../Rules:301: recipe for target '/scratch/jmyers/glibc-bot/build/glibcs/loongarch64-linux-gnu-lp64d/glibc/elf/ifuncmain1static' failed
> 
> But it also causes the second GCC build in the build-many-glibcs.py 
> "compilers" build to fail, if such a build is run with glibc including
> this change.

On my system I get a better error message:

/home/xry111/git-repos/glibc-t/install/compilers/loongarch64-linux-gnu-lp64d/sysroot/usr/lib64/crt1.o(.text+0x30): error: R_LARCH_SOP_PUSH_PCREL against `__libc_start_main@@GLIBC_2.36':
PLT shouldn't be with r_addend.
collect2: error: ld returned 1 exit status

Looks like crt1.o contains a PCREL relocation to __libc_start_main,
despite it's not supported by binutils-2.39 and I expected that such a
relocation should be only generated in rcrt1.o...  Will investigate.
Xi Ruoyao Oct. 2, 2022, 2:25 p.m. UTC | #7
On Sat, 2022-10-01 at 21:07 +0800, Xi Ruoyao wrote:
> On Fri, 2022-09-30 at 20:10 +0000, Joseph Myers wrote:
> > It appears this has broken the build with binutils 2.39 branch, the 
> > default used by build-many-glibcs.py.  Either the configure test
> > should be 
> > made stricter so it doesn't pass for binutils 2.39, or some relevant
> > bug 
> > fix should be backported to binutils 2.39 branch.
> > 
> > Building the glibc testsuite, the error is:
> > 
> > collect2: fatal error: ld terminated with signal 11 [Segmentation
> > fault], core dumped
> > compilation terminated.
> > ../Rules:301: recipe for target '/scratch/jmyers/glibc-
> > bot/build/glibcs/loongarch64-linux-gnu-
> > lp64d/glibc/elf/ifuncmain1static' failed
> > 
> > But it also causes the second GCC build in the build-many-glibcs.py 
> > "compilers" build to fail, if such a build is run with glibc
> > including
> > this change.
> 
> On my system I get a better error message:
> 
> /home/xry111/git-repos/glibc-t/install/compilers/loongarch64-linux-
> gnu-lp64d/sysroot/usr/lib64/crt1.o(.text+0x30): error:
> R_LARCH_SOP_PUSH_PCREL against `__libc_start_main@@GLIBC_2.36':
> PLT shouldn't be with r_addend.
> collect2: error: ld returned 1 exit status
> 
> Looks like crt1.o contains a PCREL relocation to __libc_start_main,
> despite it's not supported by binutils-2.39 and I expected that such a
> relocation should be only generated in rcrt1.o...  Will investigate.

Proposed fix at
https://sourceware.org/pipermail/libc-alpha/2022-October/142417.html.
diff mbox series

Patch

diff --git a/sysdeps/loongarch/configure b/sysdeps/loongarch/configure
index 43b54d4965..70d6fec5c1 100644
--- a/sysdeps/loongarch/configure
+++ b/sysdeps/loongarch/configure
@@ -3,3 +3,51 @@ 
 
 $as_echo "#define HIDDEN_VAR_NEEDS_DYNAMIC_RELOC 1" >>confdefs.h
 
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the toolchain is sufficient to build static PIE on LoongArch" >&5
+$as_echo_n "checking if the toolchain is sufficient to build static PIE on LoongArch... " >&6; }
+if ${libc_cv_static_pie_on_loongarch+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+  cat > conftest.S << EOF
+.global _start
+.type _start, @function
+_start:
+  li.w $a7, 93
+  /* This ensures the assembler supports explicit reloc.  */
+  pcalau12i $a0, %pc_hi20(x)
+  ld.w $a0, $a0, %pc_lo12(x)
+  syscall 0
+
+.data
+x:
+  .word 0
+  /* This should produce an R_LARCH_RELATIVE in the static PIE.  */
+  .dword _start
+EOF
+  libc_cv_static_pie_on_loongarch=no
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest conftest.S'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } \
+     && { ac_try='LC_ALL=C $READELF -Wr conftest | grep -q R_LARCH_RELATIVE'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+  then
+    libc_cv_static_pie_on_loongarch=yes
+  fi
+  rm -rf conftest.*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_static_pie_on_loongarch" >&5
+$as_echo "$libc_cv_static_pie_on_loongarch" >&6; }
+
+if test "$libc_cv_static_pie_on_loongarch" = yes; then
+  $as_echo "#define SUPPORT_STATIC_PIE 1" >>confdefs.h
+
+fi
diff --git a/sysdeps/loongarch/configure.ac b/sysdeps/loongarch/configure.ac
index f744367bf3..282b95b0fb 100644
--- a/sysdeps/loongarch/configure.ac
+++ b/sysdeps/loongarch/configure.ac
@@ -4,3 +4,39 @@  GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
 dnl It is always possible to access static and hidden symbols in an
 dnl position independent way.
 AC_DEFINE(HIDDEN_VAR_NEEDS_DYNAMIC_RELOC)
+
+dnl Test if the toolchain is new enough for static PIE.
+dnl We need a GAS supporting explicit reloc (older GAS produces stack-based
+dnl reloc and triggers an internal error in the linker).  And, we need GCC to
+dnl pass the correct linker flags for static PIE.  GCC >= 13 and GAS >= 2.40
+dnl satisify the requirement, but a distro may backport static PIE support into
+dnl earlier GCC or Binutils releases as well.
+AC_CACHE_CHECK([if the toolchain is sufficient to build static PIE on LoongArch],
+libc_cv_static_pie_on_loongarch, [
+  cat > conftest.S << EOF
+.global _start
+.type _start, @function
+_start:
+  li.w $a7, 93
+  /* This ensures the assembler supports explicit reloc.  */
+  pcalau12i $a0, %pc_hi20(x)
+  ld.w $a0, $a0, %pc_lo12(x)
+  syscall 0
+
+.data
+x:
+  .word 0
+  /* This should produce an R_LARCH_RELATIVE in the static PIE.  */
+  .dword _start
+EOF
+  libc_cv_static_pie_on_loongarch=no
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -static-pie -nostdlib -fPIE -o conftest conftest.S]) \
+     && AC_TRY_COMMAND([LC_ALL=C $READELF -Wr conftest | grep -q R_LARCH_RELATIVE])
+  then
+    libc_cv_static_pie_on_loongarch=yes
+  fi
+  rm -rf conftest.*])
+
+if test "$libc_cv_static_pie_on_loongarch" = yes; then
+  AC_DEFINE(SUPPORT_STATIC_PIE)
+fi
diff --git a/sysdeps/loongarch/start.S b/sysdeps/loongarch/start.S
index e66af16d57..05cabd9b96 100644
--- a/sysdeps/loongarch/start.S
+++ b/sysdeps/loongarch/start.S
@@ -60,9 +60,17 @@  ENTRY (ENTRY_POINT)
 	cfi_undefined (1)
 	or		a5, a0, zero /* rtld_fini */
 
+#if defined(PIC) && !defined(SHARED)
+/* For static PIE, the GOT cannot be used in _start because the GOT entries are
+   offsets instead of real addresses before __libc_start_main.  */
+# define LA la.pcrel
+#else
 /* We must get symbol main through GOT table, since main may not be local.
    For instance: googletest defines main in dynamic library.  */
-	la.got		a0, t0, main
+# define LA la.got
+#endif
+
+	LA		a0, t0, main
 	REG_L		a1, sp, 0
 	ADDI		a2, sp, SZREG
 
@@ -73,9 +81,9 @@  ENTRY (ENTRY_POINT)
 	move		a4, zero /* used to be fini */
 	or		a6, sp, zero /* stack_end */
 
-	la.got		ra, t0, __libc_start_main
+	LA		ra, t0, __libc_start_main
 	jirl		ra, ra, 0
 
-	la.got		ra, t0, abort
+	LA		ra, t0, abort
 	jirl		ra, ra, 0
 END (ENTRY_POINT)