Bug 18841 - Data relocations with IFUNC symbols can lead to segfault
Summary: Data relocations with IFUNC symbols can lead to segfault
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: 2.26
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-08-17 22:22 UTC by Alexander Monakov
Modified: 2017-08-17 14:20 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
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 cvs-commit@gcc.gnu.org 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 cvs-commit@gcc.gnu.org 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 cvs-commit@gcc.gnu.org 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 cvs-commit@gcc.gnu.org 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 cvs-commit@gcc.gnu.org 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.