Bug 27973

Summary: ld x86: Allow direct access to protected function symbols
Product: binutils Reporter: Fangrui Song <i>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: UNCONFIRMED ---    
Severity: normal CC: fweimer, hjl.tools, matz, sam, thiago
Priority: P2    
Version: unspecified   
Target Milestone: ---   
Host: Target: x86_64-*
Build: Last reconfirmed:

Description Fangrui Song 2021-06-09 17:04:58 UTC
// a.c
__attribute__((visibility("protected"))) void *foo () {
  return (void *)foo;
}

// This roughly maps to:
        .globl  foo
        .protected      foo
        .type   foo, @function
foo:
        leaq    foo(%rip), %rax

% gcc -fpic -shared -fuse-ld=bfd a.s
/usr/bin/ld.bfd: /tmp/ccWPJCLw.o: relocation R_X86_64_PC32 against protected symbol `foo' can not be used when making a shared object
/usr/bin/ld.bfd: final link failed: bad value
collect2: error: ld returned 1 exit status

The diagnostic was probably added circa 2016/2017 to make copy relocations on protected data symbols work with glibc.
It should not apply to function symbols.


The "copy relocations on protected data symbols" scheme has some fragile support with GNU ld and glibc on x86 (acked by multiple glibc maintainers).
It definitely did not work before circa 2016, and should not work in the future.
This scheme does not work with gold or LLD.
GNU ld for non-x86 architectures don't work.
I think no software will break if we drop the fragile glibc support.
Comment 1 Sourceware Commits 2021-06-17 17:26: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=b6b42983720c2d88f680ef7679f41c3ff95daae1

commit b6b42983720c2d88f680ef7679f41c3ff95daae1
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Jun 17 10:19:29 2021 -0700

    x86-64: Test protected function pointers
    
    On x86-64, function pointers in executable for external funtions may be
    resolved to their PLT entries in executable.  If it happens, function
    pointers of protected funtions in shared libraries must be resolved to
    the PLT entries in executable, not addresses of protected funtions in
    shared libraries.
    
            PR ld/27973
            * testsuite/ld-x86-64/x86-64.exp: Run protected function tests.
            * testsuite/ld-x86-64/protected-func-1.h: New file.
            * testsuite/ld-x86-64/protected-func-1a.s: Likewise.
            * testsuite/ld-x86-64/protected-func-1b.c: Likewise.
Comment 2 Sourceware Commits 2021-06-17 17:36:39 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=e013d20dc73b40d4b70c4a366c9adc619503e66b

commit e013d20dc73b40d4b70c4a366c9adc619503e66b
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Jun 17 10:32:27 2021 -0700

    x86-64: Use $NOPIE_LDFLAGS/$NOPIE_CFLAGS on protected-func-1
    
            PR ld/27973
            * testsuite/ld-x86-64/x86-64.exp: Pass $NOPIE_LDFLAGS and
            $NOPIE_CFLAGS to protected-func-1 without PIE.
Comment 3 H.J. Lu 2021-06-17 17:37:59 UTC
If you create a non-PIE run-time test, you will see the run-time failure
with GCC 11.
Comment 4 H.J. Lu 2021-06-17 17:39:37 UTC
In executable, without PIE, there is

0000000000401040 <protected_func_1a@plt>:
  401040:	ff 25 da 2f 00 00    	jmp    *0x2fda(%rip)        # 404020 <pr
otected_func_1a@Base>
  401046:	68 01 00 00 00       	push   $0x1
  40104b:	e9 d0 ff ff ff       	jmp    401020 <_init+0x20>

which is used as function pointer value.