configure: fix STT_GNU_IFUNC support detection with PIE toolchains [BZ #25506]

Message ID 20200204220651.4006526-1-aurelien@aurel32.net
State Committed
Headers

Commit Message

Aurelien Jarno Feb. 4, 2020, 10:06 p.m. UTC
  When GCC defaults to PIE, compiling the conftest.S that is used to
detect for assembler and linker STT_GNU_IFUNC support emits a
relocation. This causes a false positive in the detection.

Example on riscv64 with a toolchain defaulting to PIE:

| configure:4009: checking for assembler and linker STT_GNU_IFUNC support
|
| Relocation section '.rela.dyn' at offset 0x268 contains 1 entry:
|    Offset          Info           Type           Sym. Value    Sym. Name + Addend
| 000000002000  000000000003 R_RISCV_RELATIVE                     280
| configure:4040: result: yes

This is also reproducible on MIPS.

Fix that by compiling conftest.S with -no-pie. After that change:

| configure:4009: checking for assembler and linker STT_GNU_IFUNC support
|
| There are no relocations in this file.
| configure:4040: result: no

Thanks to Andreas Schwab for the help debugging the issue.

---
 configure    | 2 +-
 configure.ac | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
  

Comments

Fangrui Song Feb. 5, 2020, 4:13 a.m. UTC | #1
On 2020-02-04, Aurelien Jarno wrote:
>When GCC defaults to PIE, compiling the conftest.S that is used to
>detect for assembler and linker STT_GNU_IFUNC support emits a
>relocation. This causes a false positive in the detection.
>
>Example on riscv64 with a toolchain defaulting to PIE:
>
>| configure:4009: checking for assembler and linker STT_GNU_IFUNC support
>|
>| Relocation section '.rela.dyn'@offset 0x268 contains 1 entry:
>|    Offset          Info           Type           Sym. Value    Sym. Name + Addend
>| 000000002000  000000000003 R_RISCV_RELATIVE                     280
>| configure:4040: result: yes

This patch is incorrect.

   .type foo,%gnu_indirect_function
   foo:
   .globl _start
   _start:
   .globl __start
   __start:
   
   .data
   .quad foo

The conftest tests a non-GOT-non-PLT relocation referencing a non-preemptible symbol causes the creation of R_*_IRELATIVE.

A better test is to check R_*_IRELATIVE, instead of expecting "no relocations".

The linker you use may not support ifunc.

(I know that lld does not support R_RISCV_IRELATIVE, and I am now
working on a fix. It will not be included in lld 10.0.0, though.)

>This is also reproducible on MIPS.
>
>Fix that by compiling conftest.S with -no-pie. After that change:
>
>| configure:4009: checking for assembler and linker STT_GNU_IFUNC support
>|
>| There are no relocations in this file.
>| configure:4040: result: no
>
>Thanks to Andreas Schwab for the help debugging the issue.
>
>---
> configure    | 2 +-
> configure.ac | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
>diff --git a/configure b/configure
>index b959d2d9885..b31b56567ab 100755
>--- a/configure
>+++ b/configure
>@@ -4031,7 +4031,7 @@ __start:
> EOF
> libc_cv_ld_gnu_indirect_function=no
> if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
>-	    -nostartfiles -nostdlib $no_ssp \
>+	    -nostartfiles -nostdlib $no_ssp -no-pie \
> 	    -o conftest conftest.S 1>&5 2>&5; then
>   # Do a link to see if the backend supports IFUNC relocs.
>   $READELF -r conftest 1>&5
>diff --git a/configure.ac b/configure.ac
>index 49b900c1ed6..8e19341f595 100644
>--- a/configure.ac
>+++ b/configure.ac
>@@ -645,7 +645,7 @@ __start:
> EOF
> libc_cv_ld_gnu_indirect_function=no
> if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
>-	    -nostartfiles -nostdlib $no_ssp \
>+	    -nostartfiles -nostdlib $no_ssp -no-pie \
> 	    -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
>   # Do a link to see if the backend supports IFUNC relocs.
>   $READELF -r conftest 1>&AS_MESSAGE_LOG_FD
>-- 
>2.24.1

Also -nostdlib = -nostartfiles + -nodefaultlibs

-nostartfiles -nostdlib is redundant.
  
Fangrui Song Feb. 5, 2020, 4:50 a.m. UTC | #2
On 2020-02-04, Fangrui Song wrote:
>On 2020-02-04, Aurelien Jarno wrote:
>>When GCC defaults to PIE, compiling the conftest.S that is used to
>>detect for assembler and linker STT_GNU_IFUNC support emits a
>>relocation. This causes a false positive in the detection.
>>
>>Example on riscv64 with a toolchain defaulting to PIE:
>>
>>| configure:4009: checking for assembler and linker STT_GNU_IFUNC support
>>|
>>| Relocation section '.rela.dyn'@offset 0x268 contains 1 entry:
>>|    Offset          Info           Type           Sym. Value    Sym. Name + Addend
>>| 000000002000  000000000003 R_RISCV_RELATIVE                     280
>>| configure:4040: result: yes
>
>This patch is incorrect.
>
>  .type foo,%gnu_indirect_function
>  foo:
>  .globl _start
>  _start:
>  .globl __start
>  __start:
>  .data
>  .quad foo
>
>The conftest tests a non-GOT-non-PLT relocation referencing a non-preemptible symbol causes the creation of R_*_IRELATIVE.
>
>A better test is to check R_*_IRELATIVE, instead of expecting "no relocations".
>
>The linker you use may not support ifunc.

Just realized that R_RISCV_IRELATIVE is not defined...

Created https://github.com/riscv/riscv-elf-psabi-doc/pull/131 to define
the constant

Created https://reviews.llvm.org/D74022 for the lld patch.

We also need a binutils-gdb side change.

>
>(I know that lld does not support R_RISCV_IRELATIVE, and I am now
>working on a fix. It will not be included in lld 10.0.0, though.)
>
>>This is also reproducible on MIPS.
>>
>>Fix that by compiling conftest.S with -no-pie. After that change:
>>
>>| configure:4009: checking for assembler and linker STT_GNU_IFUNC support
>>|
>>| There are no relocations in this file.
>>| configure:4040: result: no
>>
>>Thanks to Andreas Schwab for the help debugging the issue.
>>
>>---
>>configure    | 2 +-
>>configure.ac | 2 +-
>>2 files changed, 2 insertions(+), 2 deletions(-)
>>
>>diff --git a/configure b/configure
>>index b959d2d9885..b31b56567ab 100755
>>--- a/configure
>>+++ b/configure
>>@@ -4031,7 +4031,7 @@ __start:
>>EOF
>>libc_cv_ld_gnu_indirect_function=no
>>if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
>>-	    -nostartfiles -nostdlib $no_ssp \
>>+	    -nostartfiles -nostdlib $no_ssp -no-pie \
>>	    -o conftest conftest.S 1>&5 2>&5; then
>>  # Do a link to see if the backend supports IFUNC relocs.
>>  $READELF -r conftest 1>&5
>>diff --git a/configure.ac b/configure.ac
>>index 49b900c1ed6..8e19341f595 100644
>>--- a/configure.ac
>>+++ b/configure.ac
>>@@ -645,7 +645,7 @@ __start:
>>EOF
>>libc_cv_ld_gnu_indirect_function=no
>>if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
>>-	    -nostartfiles -nostdlib $no_ssp \
>>+	    -nostartfiles -nostdlib $no_ssp -no-pie \
>>	    -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
>>  # Do a link to see if the backend supports IFUNC relocs.
>>  $READELF -r conftest 1>&AS_MESSAGE_LOG_FD
>>-- 
>>2.24.1
>
>Also -nostdlib = -nostartfiles + -nodefaultlibs
>
>-nostartfiles -nostdlib is redundant.
  
Aurelien Jarno Feb. 5, 2020, 6:15 a.m. UTC | #3
On 2020-02-04 20:13, Fangrui Song wrote:
> On 2020-02-04, Aurelien Jarno wrote:
> > When GCC defaults to PIE, compiling the conftest.S that is used to
> > detect for assembler and linker STT_GNU_IFUNC support emits a
> > relocation. This causes a false positive in the detection.
> > 
> > Example on riscv64 with a toolchain defaulting to PIE:
> > 
> > | configure:4009: checking for assembler and linker STT_GNU_IFUNC support
> > |
> > | Relocation section '.rela.dyn'@offset 0x268 contains 1 entry:
> > |    Offset          Info           Type           Sym. Value    Sym. Name + Addend
> > | 000000002000  000000000003 R_RISCV_RELATIVE                     280
> > | configure:4040: result: yes
> 
> This patch is incorrect.
> 
>   .type foo,%gnu_indirect_function
>   foo:
>   .globl _start
>   _start:
>   .globl __start
>   __start:
>   .data
>   .quad foo
> 
> The conftest tests a non-GOT-non-PLT relocation referencing a non-preemptible symbol causes the creation of R_*_IRELATIVE.
> 
> A better test is to check R_*_IRELATIVE, instead of expecting "no relocations".

This is not something possible for two reasons:
- when building with PIE, the output is actually "no relocations".
- this test is not RISC-V specific

I realized in the meantime this bug is actually the reason why we have
been forcing -no-pie when building GNU libc on Debian MIPS. With -pie
the output is:

Relocation section '.rel.dyn' at offset 0x2fc contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
 00000000  00000000 R_MIPS_NONE      
 00010310  00000003 R_MIPS_REL32  

Aurelien
  
Aurelien Jarno Feb. 5, 2020, 6:24 a.m. UTC | #4
On 2020-02-05 07:15, Aurelien Jarno wrote:
> On 2020-02-04 20:13, Fangrui Song wrote:
> > On 2020-02-04, Aurelien Jarno wrote:
> > > When GCC defaults to PIE, compiling the conftest.S that is used to
> > > detect for assembler and linker STT_GNU_IFUNC support emits a
> > > relocation. This causes a false positive in the detection.
> > > 
> > > Example on riscv64 with a toolchain defaulting to PIE:
> > > 
> > > | configure:4009: checking for assembler and linker STT_GNU_IFUNC support
> > > |
> > > | Relocation section '.rela.dyn'@offset 0x268 contains 1 entry:
> > > |    Offset          Info           Type           Sym. Value    Sym. Name + Addend
> > > | 000000002000  000000000003 R_RISCV_RELATIVE                     280
> > > | configure:4040: result: yes
> > 
> > This patch is incorrect.
> > 
> >   .type foo,%gnu_indirect_function
> >   foo:
> >   .globl _start
> >   _start:
> >   .globl __start
> >   __start:
> >   .data
> >   .quad foo
> > 
> > The conftest tests a non-GOT-non-PLT relocation referencing a non-preemptible symbol causes the creation of R_*_IRELATIVE.
> > 
> > A better test is to check R_*_IRELATIVE, instead of expecting "no relocations".
> 
> This is not something possible for two reasons:
> - when building with PIE, the output is actually "no relocations".
> - this test is not RISC-V specific

Oh I have seen your patch now. It makes sense now, sorry about the
confusion.

I have tested it quickly on x86-64, MIPS, aarch64, it seems to work as
expected.
  

Patch

diff --git a/configure b/configure
index b959d2d9885..b31b56567ab 100755
--- a/configure
+++ b/configure
@@ -4031,7 +4031,7 @@  __start:
 EOF
 libc_cv_ld_gnu_indirect_function=no
 if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
-	    -nostartfiles -nostdlib $no_ssp \
+	    -nostartfiles -nostdlib $no_ssp -no-pie \
 	    -o conftest conftest.S 1>&5 2>&5; then
   # Do a link to see if the backend supports IFUNC relocs.
   $READELF -r conftest 1>&5
diff --git a/configure.ac b/configure.ac
index 49b900c1ed6..8e19341f595 100644
--- a/configure.ac
+++ b/configure.ac
@@ -645,7 +645,7 @@  __start:
 EOF
 libc_cv_ld_gnu_indirect_function=no
 if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
-	    -nostartfiles -nostdlib $no_ssp \
+	    -nostartfiles -nostdlib $no_ssp -no-pie \
 	    -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
   # Do a link to see if the backend supports IFUNC relocs.
   $READELF -r conftest 1>&AS_MESSAGE_LOG_FD