Bug 18841

Summary: Data relocations with IFUNC symbols can lead to segfault
Product: binutils Reporter: Alexander Monakov <amonakov>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: amodra, hjl.tools
Priority: P2    
Version: unspecified   
Target Milestone: 2.26   
Host: Target:
Build: Last reconfirmed:

Description Alexander Monakov 2015-08-17 22:22:29 UTC
In the following testcase, libfoo.so is compiled so that it has GLOB_DAT relocations against 'foo' and 'zoo', in that order (with BFD linker), which leads to failure at dynamic linking time.  Renaming 'zoo' to 'z' with the preprocessor avoids the segfault (the relocations happen to be emitted in the opposite order).  Gold linker appears to always sort the relocations "properly".

cat <<EOF >foo.c
void foo() __attribute__((ifunc("resolve_foo")));

static void foo_impl() {}

void test()
{
  void (*pg)(void) = foo;
  pg();
}

static void* resolve_foo()
{
  extern void zoo(void);

  void (*pz)(void) = zoo;
  pz();
  return foo_impl;
}
EOF

cat <<EOF >main.c
void zoo(){}

void test(void);

int main()
{
  test();
  return 0;
}
EOF

cat <<'EOF' >Makefile
test: main; ./main

main: libfoo.so

lib%.so: %.c; $(CC) $(CFLAGS) -fPIC -shared -o $@ $<

main: LDLIBS=-L. -lfoo

main: LDFLAGS=-Wl,-rpath,.
EOF

$ make -B CFLAGS=-fuse-ld=gold
cc -fuse-ld=gold -fPIC -shared -o libfoo.so foo.c
cc -fuse-ld=gold  -Wl,-rpath,.  main.c libfoo.so  -L. -lfoo -o main
./main
$ make -B CFLAGS=-fuse-ld=bfd
cc -fuse-ld=bfd -fPIC -shared -o libfoo.so foo.c
cc -fuse-ld=bfd  -Wl,-rpath,.  main.c libfoo.so  -L. -lfoo -o main
./main
Makefile:2: recipe for target 'test' failed
make: *** [test] Segmentation fault
$ make -B CFLAGS=-fuse-ld=bfd\ -Dzoo=z
cc -fuse-ld=bfd -Dzoo=z -fPIC -shared -o libfoo.so foo.c
cc -fuse-ld=bfd -Dzoo=z  -Wl,-rpath,.  main.c libfoo.so  -L. -lfoo -o main
./main
$
Comment 1 H.J. Lu 2015-08-17 23:28:31 UTC
This usage is ill defined. Small changes change the run-time
behavior:

1. Use -O2 causes it to pass with ld:

[hjl@gnu-6 pr18841]$ make 
gcc -B./ -O2 -g   -c -o main.o main.c
gcc -B./ -O2 -g -fpic   -c -o foo.o foo.c
gcc -B./  -shared -o libfoo.so foo.o
gcc -B./  -o main main.o libfoo.so -Wl,-R.
./main
[hjl@gnu-6 pr18841]$ 

2. Make pz file scope causes it to fail with gold and ld:

[hjl@gnu-6 pr18841-bad]$ cat foo.c
void foo() __attribute__((ifunc("resolve_foo")));

static void foo_impl() {}

extern void zoo(void);
void (*pz)(void) = zoo;

void test()
{
  void (*pg)(void) = foo;
  pg();
}

static void* resolve_foo()
{
  pz();
  return foo_impl;
}
[hjl@gnu-6 pr18841-bad]$ make
gcc -B./ -fuse-ld=gold -g -fpic   -c -o foo.o foo.c
gcc -B./ -fuse-ld=gold  -shared -o libfoo.so foo.o
gcc -B./ -fuse-ld=gold  -o main main.o libfoo.so -Wl,-R.
./main
Makefile:17: recipe for target 'all' failed
make: *** [all] Segmentation fault
[hjl@gnu-6 pr18841-bad]$
Comment 2 Alan Modra 2015-08-18 06:37:26 UTC
The problem here is that x86_64 doesn't properly sort ifunc relocs last.  elf_x86_64_reloc_type_class needs to return reloc_class_ifunc for relocs against ifunc symbols.
Comment 3 Sourceware Commits 2015-08-18 16:52:08 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=cae1fbbb7e3d770702a0d7a5027b46835e6adc13

commit cae1fbbb7e3d770702a0d7a5027b46835e6adc13
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Aug 18 09:47:59 2015 -0700

    Return reloc_class_ifunc for reloc against IFUNC
    
    elf_XXX_reloc_type_class should return reloc_class_ifunc for relocation
    against STT_GNU_IFUNC symbol.
    
    bfd/
    
    	PR ld/18841
    	* elf-bfd.h (elf_link_hash_table): Add dynsym.
    	* elf32-i386.c (elf_i386_reloc_type_class): Return
    	reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol.
    	* elf64-x86-64.c (elf_x86_64_reloc_type_class): Likewise.
    	* elflink.c (_bfd_elf_link_create_dynamic_sections): Set dynsym.
    	(bfd_elf_size_dynsym_hash_dynstr): Use dynsym.
    	(elf_final_link_info): Remove dynsym_sec.
    	(elf_link_output_extsym): Replace dynsym_sec with dynsym.
    	(bfd_elf_final_link): Remove reference to dynsym_sec.  Replace
    	dynsym_sec with dynsym.
    
    ld/testsuite/
    
    	PR ld/18841
    	* ld-ifunc/ifunc.exp: Add a test for PR ld/18841.
    	* ld-ifunc/pr18841.out: New file.
    	* ld-ifunc/pr18841a.c: Likewise.
    	* ld-ifunc/pr18841b.c: Likewise.
Comment 4 H.J. Lu 2015-08-18 16:53:15 UTC
Fixed.
Comment 5 Alexander Monakov 2015-08-18 17:26:43 UTC
Does it still fail with the change you mentioned in comment #2?

> 2. Make pz file scope causes it to fail with gold and ld
Comment 6 H.J. Lu 2015-08-18 17:28:35 UTC
(In reply to Alexander Monakov from comment #5)
> Does it still fail with the change you mentioned in comment #2?
> 
> > 2. Make pz file scope causes it to fail with gold and ld

Yes.
Comment 7 H.J. Lu 2015-08-18 17:33:21 UTC
(In reply to H.J. Lu from comment #6)
> (In reply to Alexander Monakov from comment #5)
> > Does it still fail with the change you mentioned in comment #2?
> > 
> > > 2. Make pz file scope causes it to fail with gold and ld
> 
> Yes.

I was wrong.  It works with ld.
Comment 8 Sourceware Commits 2015-08-18 17:44:41 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4e1626f5a8d73573d6cf593fabe5bc80f7b3e04e

commit 4e1626f5a8d73573d6cf593fabe5bc80f7b3e04e
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Aug 18 10:43:19 2015 -0700

    Add another test for PR ld/18841
    
    	PR ld/18841
    	* ld-ifunc/ifunc.exp: Add another test for PR ld/18841.
    	* ld-ifunc/pr18841c.c: New file.
Comment 9 Sourceware Commits 2015-10-22 08:16:37 UTC
The master branch has been updated by Andreas Krebbel <krebbel@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0f042c67a04d5d0c8f879c27d651a7ed5aa6566f

commit 0f042c67a04d5d0c8f879c27d651a7ed5aa6566f
Author: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
Date:   Thu Oct 22 10:11:07 2015 +0200

    S/390: ifunc: Fix PR18841.
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for x86.
    
    bfd/ChangeLog:
    
    	PR ld/18841
    	* elf32-s390.c (elf_s390_reloc_type_class): Return
    	reloc_class_ifunc for ifunc symbols.
    	* elf64-s390.c (elf_s390_reloc_type_class): Likewise.
Comment 10 Sourceware Commits 2017-07-19 17:49:27 UTC
The master branch has been updated by Szabolcs Nagy <nsz@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f2e6a8430e72d58e70aaaaefbb32dc3953d5cf33

commit f2e6a8430e72d58e70aaaaefbb32dc3953d5cf33
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Tue Jul 4 15:43:59 2017 +0100

    [AArch64] Fix PR18841 ifunc relocation ordering
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for x86.
    
    Fixes
    FAIL: Run pr18841 with libpr18841c.so
    
    bfd/
    	PR ld/18841
    	* elfnn-aarch64.c (elfNN_aarch64_reloc_type_class): Return
    	reloc_class_ifunc for ifunc symbols.
Comment 11 Sourceware Commits 2017-08-17 14:20:15 UTC
The binutils-2_29-branch branch has been updated by Szabolcs Nagy <nsz@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6f0f222468cd8cf23cbe2458be233c553842a568

commit 6f0f222468cd8cf23cbe2458be233c553842a568
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Tue Jul 4 15:43:59 2017 +0100

    [AArch64] Fix PR18841 ifunc relocation ordering
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for x86.
    
    Fixes
    FAIL: Run pr18841 with libpr18841c.so
    
    bfd/
    	PR ld/18841
    	* elfnn-aarch64.c (elfNN_aarch64_reloc_type_class): Return
    	reloc_class_ifunc for ifunc symbols.
Comment 12 Sourceware Commits 2019-02-07 16:06:12 UTC
The master branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b2abe1bd8149dd9ad64432f620c3a034bf23a5fe

commit b2abe1bd8149dd9ad64432f620c3a034bf23a5fe
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 7 17:04:31 2019 +0100

    SPARC: fix PR ld/18841
    
    This fixes the last ld failures on SPARC64/Linux:
    
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
    by mimicing what has been done on x86-64 and Aarch64 to fix the PR.
    
    bfd/
    	PR ld/18841
            * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
            * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
Comment 13 Sourceware Commits 2019-02-07 16:12:02 UTC
The binutils-2_32-branch branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=afbdeb58468604ede2d51fb00c4ea9850fcf2617

commit afbdeb58468604ede2d51fb00c4ea9850fcf2617
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 7 17:04:31 2019 +0100

    SPARC: fix PR ld/18841
    
    This fixes the last ld failures on SPARC64/Linux:
    
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
    by mimicing what has been done on x86-64 and Aarch64 to fix the PR.
    
    bfd/
    	PR ld/18841
            * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
            * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
Comment 14 Sourceware Commits 2019-02-07 16:15:22 UTC
The binutils-2_31-branch branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1532a937c64105681d74055389f0e846244fb830

commit 1532a937c64105681d74055389f0e846244fb830
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 7 17:04:31 2019 +0100

    SPARC: fix PR ld/18841
    
    This fixes the last ld failures on SPARC64/Linux:
    
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
    by mimicing what has been done on x86-64 and Aarch64 to fix the PR.
    
    bfd/
    	PR ld/18841
            * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
            * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
Comment 15 Sourceware Commits 2020-07-09 13:28:42 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=470cd0faa7f433b47944683eee4fc3dad6ef7cdf

commit 470cd0faa7f433b47944683eee4fc3dad6ef7cdf
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Jul 9 16:35:27 2020 +0930

    pr18841 tests on powerpc64
    
    The PR18841 test does cross-module calls from within an ifunc
    resolver, which is nasty, and not supported in general since the
    called function may not be relocated.  In this case the called
    function (zoo) is just a stub so doesn't need relocating, but on ppc64
    the function descriptor for zoo in the executable won't be relocated
    at the time the shared library ifunc resolver runs.  That means the
    test will fail if your compiler generates PIEs by default.
    
            PR 18841
            * testsuite/ld-ifunc/ifunc.exp: Run pr18841 tests non-pie.
Comment 16 Sourceware Commits 2020-07-13 14:26:13 UTC
The binutils-2_35-branch branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3d186ccca35dfd7e9e5ae1eaba3015d0ae17e247

commit 3d186ccca35dfd7e9e5ae1eaba3015d0ae17e247
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Jul 9 16:35:27 2020 +0930

    pr18841 tests on powerpc64
    
    The PR18841 test does cross-module calls from within an ifunc
    resolver, which is nasty, and not supported in general since the
    called function may not be relocated.  In this case the called
    function (zoo) is just a stub so doesn't need relocating, but on ppc64
    the function descriptor for zoo in the executable won't be relocated
    at the time the shared library ifunc resolver runs.  That means the
    test will fail if your compiler generates PIEs by default.
    
            PR 18841
            * testsuite/ld-ifunc/ifunc.exp: Run pr18841 tests non-pie.
    
    (cherry picked from commit 470cd0faa7f433b47944683eee4fc3dad6ef7cdf)
Comment 17 Sourceware Commits 2023-01-09 15:52:10 UTC
The master branch has been updated by Christophe Lyon <clyon@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=2b70b1b838388cc4186933a724eccd0be6b2a955

commit 2b70b1b838388cc4186933a724eccd0be6b2a955
Author: Christophe Lyon <christophe.lyon@arm.com>
Date:   Mon Jan 2 15:46:31 2023 +0000

    Fix PR18841 ifunc relocation ordering
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for AArch64.
    
    Fixes:
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
            bfd/
            PR ld/18841
            * elf32-arm.c (elf32_arm_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
    
            ld/testsuite/
            * ld-arm/ifunc-12.rd: Update relocations order.
            * ld-arm/ifunc-3.rd: Likewise.
            * ld-arm/ifunc-4.rd: Likewise.
Comment 18 Sourceware Commits 2023-01-09 15:53:32 UTC
The binutils-2_40-branch branch has been updated by Christophe Lyon <clyon@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5d546b26ceca0e10c51c04b895d83b1460ea38c6

commit 5d546b26ceca0e10c51c04b895d83b1460ea38c6
Author: Christophe Lyon <christophe.lyon@arm.com>
Date:   Mon Jan 2 15:46:31 2023 +0000

    Fix PR18841 ifunc relocation ordering
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for AArch64.
    
    Fixes:
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
            bfd/
            PR ld/18841
            * elf32-arm.c (elf32_arm_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
    
            ld/testsuite/
            * ld-arm/ifunc-12.rd: Update relocations order.
            * ld-arm/ifunc-3.rd: Likewise.
            * ld-arm/ifunc-4.rd: Likewise.