Bug 23169

Summary: IFUNC pointer should be allowed in executable
Product: binutils Reporter: H.J. Lu <hjl.tools>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: emaste, i, sam
Priority: P2    
Version: 2.31   
Target Milestone: 2.31   
See Also: https://sourceware.org/bugzilla/show_bug.cgi?id=30698
Host: Target:
Build: Last reconfirmed:

Description H.J. Lu 2018-05-11 16:12:47 UTC
[hjl@gnu-cfl-1 ifunc-exec]$ cat main.c 
extern int (*func_p) (void);
extern int func (void);
extern void foo (void);


void
bar (void)
{
  if (func_p != &func || func_p () != 0xbadbeef)
    __builtin_abort ();
}

int
main ()
{
  func_p = &func;
  foo ();
  bar ();
  return 0;
}
[hjl@gnu-cfl-1 ifunc-exec]$ cat func.c 
static int
ifunc (void)
{
  return 0xbadbeef;
}

void func(void) __attribute__((ifunc("resolve_func")));

static void *
resolve_func (void)
{
  return ifunc;
}
[hjl@gnu-cfl-1 ifunc-exec]$ cat foo.c 
int (*func_p) (void);
extern int func (void);

void
foo (void)
{
  if (func_p != &func || func_p () != 0xbadbeef)
    __builtin_abort ();
}
[hjl@gnu-cfl-1 ifunc-exec]$ make
gcc -g   -c -o main.o main.c
gcc -g   -c -o func.o func.c
gcc -g -fPIC   -c -o foo.o foo.c
gcc -shared -o libfoo.so foo.o
gcc -o x main.o func.o libfoo.so -Wl,-R,.
/usr/local/bin/ld: dynamic STT_GNU_IFUNC symbol `func' with pointer equality in `func.o' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
make: *** [Makefile:17: x] Error 1
[hjl@gnu-cfl-1 ifunc-exec]$

If STT_GNU_IFUNC symbol is defined in executable, backend should change
it to the normal function and set its address to its PLT entry which should
be resolved by R_*_IRELATIVE at run-time.  All external references should
be resolved to its PLT in executable.
Comment 1 Sourceware Commits 2018-05-14 11:03:30 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=4ec0995016801cc5d5cf13baf6e10163861e6852

commit 4ec0995016801cc5d5cf13baf6e10163861e6852
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon May 14 03:55:37 2018 -0700

    x86; Allow IFUNC pointer defined in PDE
    
    If IFUNC symbol is defined in position-dependent executable, we should
    change it to the normal function and set its address to its PLT entry
    which should be resolved by R_*_IRELATIVE at run-time.  All external
    references should be resolved to its PLT in executable.
    
    bfd/
    
    	PR ld/23169
    	* elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Don't issue
    	an error on IFUNC pointer defined in PDE.
    	* elf32-i386.c (elf_i386_finish_dynamic_symbol): Call
    	_bfd_x86_elf_link_fixup_ifunc_symbol.
    	* elf64-x86-64.c (elf_x86_64_finish_dynamic_symbol): Likewise.
    	* elfxx-x86.c (_bfd_x86_elf_link_fixup_ifunc_symbol): New
    	function.
    	* elfxx-x86.h (_bfd_x86_elf_link_fixup_ifunc_symbol): New.
    
    ld/
    
    	PR ld/23169
    	* testsuite/ld-ifunc/ifunc-9-i386.d: New file.
    	* testsuite/ld-ifunc/ifunc-9-x86-64.d: Likewise.
    	* testsuite/ld-ifunc/pr23169a.c: Likewise.
    	* testsuite/ld-ifunc/pr23169a.rd: Likewise.
    	* testsuite/ld-ifunc/pr23169b.c: Likewise.
    	* testsuite/ld-ifunc/pr23169b.c: Likewise.
    	* testsuite/ld-ifunc/pr23169c.rd: Likewise.
    	* testsuite/ld-ifunc/pr23169c.rd: Likewise.
    	* testsuite/ld-ifunc/ifunc-9-x86.d: Removed.
    	* testsuite/ld-ifunc/ifunc.exp: Run PR ld/23169 tests.
Comment 2 H.J. Lu 2018-05-14 11:05:45 UTC
Fixed for 2.31.
Comment 3 Sourceware Commits 2018-06-26 11:59:29 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 2822b09ff6024d042f1258194d6938c5a401b4fb
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Jun 26 14:30:16 2018 +0930

    PR23169 bogus test
    
    The testcase isn't valid.  If it happens to run on your target, you're
    lucky.
    
    	PR 23169
    	* testsuite/ld-ifunc/ifunc.exp: Don't run pr23169 tests on
    	powerpc.  Comment.
Comment 4 Sourceware Commits 2018-06-26 13:51:31 UTC
The binutils-2_31-branch branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 83195288b7af4d5f2edfed35a20cbf4d59cb4996
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Jun 26 14:30:16 2018 +0930

    PR23169 bogus test
    
    The testcase isn't valid.  If it happens to run on your target, you're
    lucky.
    
    	PR 23169
    	* testsuite/ld-ifunc/ifunc.exp: Don't run pr23169 tests on
    	powerpc.  Comment.
Comment 5 Sourceware Commits 2018-07-20 15:37:33 UTC
The master branch has been updated by Andre Simoes Dias Vieira <avieira@sourceware.org>:

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

commit 3ba174474d3cc063d6b7abf0bfdd6021bbaf8a90
Author: Andre Simoes Dias Vieira <andre.simoesdiasvieira@arm.com>
Date:   Thu Jul 19 16:18:28 2018 +0100

    [PATCH, LD, AArch64] Fix ifunc testisms
    
    This patch fixes some ifunc testisms after H.J. Lu's patch to enable the
    use of IFUNC pointers in position dependent code for binutils. See PR
    LD/23169 in binutils bugzilla.
    
    The aarch64 ifunc error message test was changed to no longer expect
    this error message as this is now an accepted combination. This patch
    also disables the executable tests added by H.J. Lu for aarch64, just as
    Alan Modra did with his patch, as these tests only seem to work on some
    architectures.
    
    ld/ChangeLog:
    2018-07-19  Andre Vieira  <andre.simoesdiasvieira@arm.com>
    
    	* testsuite/ld-aarch64/ifunc-9.d: Remove no longer expected error.
    	* testsuite/ld-ifunc/ifunc.exp: Disable tests for aarch64.
Comment 6 Sourceware Commits 2018-08-01 20:41:19 UTC
The binutils-2_31-branch branch has been updated by Roland McGrath <roland@sourceware.org>:

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

commit feaed904944b4c07c1335b81f0fc27b5988e33c8
Author: Andre Simoes Dias Vieira <andre.simoesdiasvieira@arm.com>
Date:   Thu Jul 19 16:18:28 2018 +0100

    [PATCH, LD, AArch64] Fix ifunc testisms
    
    This patch fixes some ifunc testisms after H.J. Lu's patch to enable the
    use of IFUNC pointers in position dependent code for binutils. See PR
    LD/23169 in binutils bugzilla.
    
    The aarch64 ifunc error message test was changed to no longer expect
    this error message as this is now an accepted combination. This patch
    also disables the executable tests added by H.J. Lu for aarch64, just as
    Alan Modra did with his patch, as these tests only seem to work on some
    architectures.
    
    ld/ChangeLog:
    2018-07-19  Andre Vieira  <andre.simoesdiasvieira@arm.com>
    
    	* testsuite/ld-aarch64/ifunc-9.d: Remove no longer expected error.
    	* testsuite/ld-ifunc/ifunc.exp: Disable tests for aarch64.
    
    (cherry picked from commit 3ba174474d3cc063d6b7abf0bfdd6021bbaf8a90)
Comment 7 Sourceware Commits 2021-01-16 15:06:00 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=75a933f39918ce4f4b9481234992895e022787ee

commit 75a933f39918ce4f4b9481234992895e022787ee
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sat Jan 16 07:00:09 2021 -0800

    ld/elf/x86: Don't compare IFUNC address in the shared object
    
    On x86, glibc 2.33 starts to issue a fatal error message when calling
    IFUNC function defined in the unrelocated executable from a shared
    library.
    
    1. Update x86 ELF linker to always convert IFUNC function defined in
    position-dependent executable (PDE) to the normal function.  GOT in PDE
    will be updated by R_*_IRELATIVE at run-time.
    2. Update PR ld/23169 tests not to compare function address of external
    IFUNC function in the shared object to avoid calling the IFUNC function
    defined in the unrelocated executable.
    3. Remove pr23169e tests which call the IFUNC function defined in the
    unrelocated position-independent executable from a shared library.
    
    bfd/
    
            PR ld/23169
            * elfxx-x86.c (_bfd_x86_elf_link_fixup_ifunc_symbol): Don't
            check pointer_equality_needed.
    
    ld/
    
            PR ld/23169
            * testsuite/ld-ifunc/ifunc.exp: Replace pr23169c.rd with
            pr23169a.rd for pr23169c and pr23169f.  Remove pr23169e tests.
            * testsuite/ld-ifunc/pr23169a.c (foo): Don't compare function
            address.
Comment 8 Fangrui Song 2021-01-17 00:32:26 UTC
Can https://sourceware.org/glibc/wiki/GNU_IFUNC to updated to document what is supported and what isn't supported?

For the https://sourceware.org/bugzilla/show_bug.cgi?id=23169#c0 example, if you run:

  gcc -fpie -g   -c -o main.o main.c
  gcc -fpie -g   -c -o func.o func.c
  gcc -g -fPIC   -c -o foo.o foo.c
  gcc -shared -o libfoo.so foo.o
  gcc -pie -o x main.o func.o libfoo.so -Wl,-R,.

Previously, a STT_GNU_IFUNC did not need to be converted to STT_FUNC if there were only GOT-generating or PLT-generating relocations.
func.o had only a GOT-generating relocation: R_X86_64_REX_GOTPCRELX. func was STT_GNU_IFUNC.

After the recent GNU ld commit https://sourceware.org/bugzilla/show_bug.cgi?id=23169#c7
STT_GNU_IFUNC is converted to STT_FUNC regardless of the relocation type.
func is STT_FUNC.

Is the idea that
(1) the main executable is relocated the last.
(2) by making the main executable STT_GNU_IFUNC STT_FUNC, ifunc resolver will not be called while the main executable is unresolved
(3) How does an ifunc resolver defined in another DSO work? Let the user ensures DT_NEEDED BFS order or the ld.so itself does topological sorting?
Comment 9 H.J. Lu 2021-01-17 16:48:02 UTC
(In reply to Fangrui Song from comment #8)
> Can https://sourceware.org/glibc/wiki/GNU_IFUNC to updated to document what
> is supported and what isn't supported?
> 

IFUNC documentation needs improvements.

> 
> Is the idea that
> (1) the main executable is relocated the last.
> (2) by making the main executable STT_GNU_IFUNC STT_FUNC, ifunc resolver
> will not be called while the main executable is unresolved

Correct.

> (3) How does an ifunc resolver defined in another DSO work? Let the user
> ensures DT_NEEDED BFS order or the ld.so itself does topological sorting?

Current ld.so issues an error with a suggestion when it detects it.
Comment 10 Sourceware Commits 2021-01-18 12:49:49 UTC
The binutils-2_36-branch branch has been updated by H.J. Lu <hjl@sourceware.org>:

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

commit e9815c344ef0d24405cfaf9968135ad2180649f8
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sat Jan 16 07:00:09 2021 -0800

    ld/elf/x86: Don't compare IFUNC address in the shared object
    
    On x86, glibc 2.33 starts to issue a fatal error message when calling
    IFUNC function defined in the unrelocated executable from a shared
    library.
    
    1. Update x86 ELF linker to always convert IFUNC function defined in
    position-dependent executable (PDE) to the normal function.  GOT in PDE
    will be updated by R_*_IRELATIVE at run-time.
    2. Update PR ld/23169 tests not to compare function address of external
    IFUNC function in the shared object to avoid calling the IFUNC function
    defined in the unrelocated executable.
    3. Remove pr23169e tests which call the IFUNC function defined in the
    unrelocated position-independent executable from a shared library.
    
    bfd/
    
            PR ld/23169
            * elfxx-x86.c (_bfd_x86_elf_link_fixup_ifunc_symbol): Don't
            check pointer_equality_needed.
    
    ld/
    
            PR ld/23169
            * testsuite/ld-ifunc/ifunc.exp: Replace pr23169c.rd with
            pr23169a.rd for pr23169c and pr23169f.  Remove pr23169e tests.
            * testsuite/ld-ifunc/pr23169a.c (foo): Don't compare function
            address.
    
    (cherry picked from commit 75a933f39918ce4f4b9481234992895e022787ee)
Comment 11 Fangrui Song 2021-01-18 19:44:23 UTC
(In reply to H.J. Lu from comment #9)
> (In reply to Fangrui Song from comment #8)
> > Can https://sourceware.org/glibc/wiki/GNU_IFUNC to updated to document what
> > is supported and what isn't supported?
> > 
> 
> IFUNC documentation needs improvements.
> 
> > 
> > Is the idea that
> > (1) the main executable is relocated the last.
> > (2) by making the main executable STT_GNU_IFUNC STT_FUNC, ifunc resolver
> > will not be called while the main executable is unresolved
> 
> Correct.
> 
> > (3) How does an ifunc resolver defined in another DSO work? Let the user
> > ensures DT_NEEDED BFS order or the ld.so itself does topological sorting?
> 
> Current ld.so issues an error with a suggestion when it detects it.

I currently cannot find a straightforward rule to explain the GNU ld behavior and what is supported in glibc.


cat > ./a.s <<eof
resolver:
  ret

.globl ifunc, _start
.type ifunc, @gnu_indirect_function
.set ifunc, resolver

_start:
  movq ifunc@GOTPCREL(%rip), %rax
  call ifunc
eof
echo 'call ifunc' > ./b.s
gcc -shared -fpic b.s -o b.so

~/Dev/binutils-gdb/Debug/ld/ld-new is a top-of-tree ld.

% ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic a.o -o a && readelf -W -s a | grep ifunc
     7: 0000000000401008     0 IFUNC   GLOBAL DEFAULT    3 ifunc
% ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic a.o ./b.so -o a && readelf -W -s a | grep ifunc
     5: 0000000000401010     0 FUNC    GLOBAL DEFAULT    7 ifunc
     8: 0000000000401010     0 FUNC    GLOBAL DEFAULT    7 ifunc

% ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic -pie a.o -o a && readelf -W --dyn-syms a | grep ifunc
     5: 0000000000001020     0 IFUNC   GLOBAL DEFAULT    8 ifunc
% ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic -pie a.o ./b.so -o a && readelf -W --dyn-syms a | grep ifunc
     5: 0000000000001020     0 IFUNC   GLOBAL DEFAULT    8 ifunc


Is this a -no-pie only behavior?
Comment 12 H.J. Lu 2021-01-18 22:26:38 UTC
(In reply to Fangrui Song from comment #11)
> (In reply to H.J. Lu from comment #9)
> 
> cat > ./a.s <<eof
> resolver:
>   ret
> 
> .globl ifunc, _start
> .type ifunc, @gnu_indirect_function
> .set ifunc, resolver
> 
> _start:
>   movq ifunc@GOTPCREL(%rip), %rax
>   call ifunc
> eof
> echo 'call ifunc' > ./b.s
> gcc -shared -fpic b.s -o b.so
> 
> ~/Dev/binutils-gdb/Debug/ld/ld-new is a top-of-tree ld.
> 
> % ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic a.o -o a && readelf -W
> -s a | grep ifunc
>      7: 0000000000401008     0 IFUNC   GLOBAL DEFAULT    3 ifunc

Symbol type in .symtab isn't relevant to ld.so.

> % ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic a.o ./b.so -o a &&
> readelf -W -s a | grep ifunc
>      5: 0000000000401010     0 FUNC    GLOBAL DEFAULT    7 ifunc
>      8: 0000000000401010     0 FUNC    GLOBAL DEFAULT    7 ifunc
> 
> % ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic -pie a.o -o a &&
> readelf -W --dyn-syms a | grep ifunc
>      5: 0000000000001020     0 IFUNC   GLOBAL DEFAULT    8 ifunc
> % ~/Dev/binutils-gdb/Debug/ld/ld-new --export-dynamic -pie a.o ./b.so -o a
> && readelf -W --dyn-syms a | grep ifunc
>      5: 0000000000001020     0 IFUNC   GLOBAL DEFAULT    8 ifunc
> 
> 
> Is this a -no-pie only behavior?

Yes.  We can do that only because position-dependent executable doesn't
need to be relocated.
Comment 13 H.J. Lu 2021-01-19 00:11:15 UTC
X86 linker uses a trick to use the PLT entry of IFUNC function in
position-dependent executable as the function address for ALL internal
and external references.  We can do that because the PLT entry doesn't
need ANY dynamic relocation.