Bug 21782

Summary: Fail to create static PIE with undefined weak symbols
Product: binutils Reporter: H.J. Lu <hjl.tools>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: i
Priority: P2    
Version: 2.30   
Target Milestone: 2.29   
Host: Target: x86-64
Build: Last reconfirmed:

Description H.J. Lu 2017-07-17 18:11:20 UTC
[hjl@gnu-6 ld]$ cat x.s
	.text
	.global _start
	.weak foo
_start:
	movl	foo(%rip), %eax
[hjl@gnu-6 ld]$ gcc -c x.s
[hjl@gnu-6 ld]$ ld -pie x.o
ld: x.o: relocation R_X86_64_PC32 against undefined symbol `foo' can not be used when making a shared object; recompile with -fPIC
ld: final link failed: Bad value
[hjl@gnu-6 ld]$
Comment 1 Sourceware Commits 2017-07-17 19:19:06 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=c5bb8910e80c6cd80c63541f86471c18375c8198

commit c5bb8910e80c6cd80c63541f86471c18375c8198
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Jul 17 12:17:59 2017 -0700

    x86-64: Limit PIC check to shared library build
    
    When building an executable, undefined symbols are error and undefined
    weak symbols are resolved to zero.  We only need to check PIC for
    building a shared library.
    
    bfd/
    
    	PR ld/21782
    	* elf64-x86-64.c (elf_x86_64_relocate_section): Limit PIC check
    	to shared library.
    
    ld/
    
    	PR ld/21782
    	* testsuite/ld-x86-64/pie3-nacl.d: New file.
    	* testsuite/ld-x86-64/pie3.d: Likewise.
    	* testsuite/ld-x86-64/pie3.s: Likewise.
    	* testsuite/ld-x86-64/x86-64.exp: Run pie3 and pie3-nacl.
Comment 2 Sourceware Commits 2017-07-17 19:41: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=8e85f840e1870b17dce6a5bdb330c5bcd85a022a

commit 8e85f840e1870b17dce6a5bdb330c5bcd85a022a
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Jul 17 12:40:57 2017 -0700

    Add missing ChangeLog entries for PR ld/21782 fix
Comment 3 Sourceware Commits 2017-07-17 19:54:54 UTC
The binutils-2_29-branch branch has been updated by H.J. Lu <hjl@sourceware.org>:

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

commit 89f512d3eca31aae9498430d3cdad6be8cf44c9a
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Jul 17 12:17:59 2017 -0700

    x86-64: Limit PIC check to shared library build
    
    When building an executable, undefined symbols are error and undefined
    weak symbols are resolved to zero.  We only need to check PIC for
    building a shared library.
    
    bfd/
    
    	PR ld/21782
    	* elf64-x86-64.c (elf_x86_64_relocate_section): Limit PIC check
    	to shared library.
    
    ld/
    
    	PR ld/21782
    	* testsuite/ld-x86-64/pie3-nacl.d: New file.
    	* testsuite/ld-x86-64/pie3.d: Likewise.
    	* testsuite/ld-x86-64/pie3.s: Likewise.
    	* testsuite/ld-x86-64/x86-64.exp: Run pie3 and pie3-nacl.
    
    (cherry picked from commit c5bb8910e80c6cd80c63541f86471c18375c8198)
Comment 4 H.J. Lu 2017-07-17 19:58:32 UTC
Fixed for 2.29.
Comment 5 H.J. Lu 2017-08-25 17:03:28 UTC
Fixed.
Comment 6 Fangrui Song 2021-07-08 19:32:24 UTC
I think suppressing the diagnostic is wrong (QoI issue).

% cat x86.s
.globl _start
.weak foo
_start:
  leaq foo(%rip), %rax
% gcc -fuse-ld=bfd -pie -nostdlib x86.s
# incorrectly passed

The correct behavior should be an error like aarch64 (and many other ports):

% cat a64.s
.globl _start
.weak foo
_start:
  adrp    x0, foo
% aarch64-linux-gnu-gcc -pie -nostdlib a64.s
/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../../aarch64-linux-gnu/bin/ld: /tmp/ccdNIlJG.o: relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol `foo' which may bind externally can not be used when making a shared object; recompile with -fPIC
/tmp/ccdNIlJG.o: in function `_start':
(.text+0x0): dangerous relocation: unsupported relocation
collect2: error: ld returned 1 exit status


The compiler uses GOT indirection for external weak objects, so being rigid for PC-relative relocation referencing an undefined weak symbol in ld isn't a compatibility problem.

% cat a.c
__attribute__((weak)) extern int var;
int *f() { return &var; }
% gcc -fpie -O2 -S a.c -o - | grep var
        movq    var@GOTPCREL(%rip), %rax
        .weak   var

---

The glibc configure-time check should be changed to use GOT:

--- i/sysdeps/x86_64/configure
+++ w/sysdeps/x86_64/configure
@@ -118,7 +118,7 @@ else
        .global _start
        .weak foo
 _start:
-       leaq    foo(%rip), %rax
+       leaq    foo@gotpcrel(%rip), %rax
 EOF
   libc_cv_pie_option="-Wl,-pie"
   if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&5'
diff --git i/sysdeps/x86_64/configure.ac w/sysdeps/x86_64/configure.ac
index ec776274af..e0639bc68e 100644
--- i/sysdeps/x86_64/configure.ac
+++ w/sysdeps/x86_64/configure.ac
@@ -64,7 +64,7 @@ cat > conftest.s <<\EOF
        .global _start
        .weak foo
 _start:
-       leaq    foo(%rip), %rax
+       leaq    foo@gotpcrel(%rip), %rax
 EOF
   libc_cv_pie_option="-Wl,-pie"
   if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&AS_MESSAGE_LOG_FD); then


I tested a trunk ld.lld (will be included in 13.0.0) which reports `error: relocation R_X86_64_PC32 cannot be used against symbol foo; recompile with -fPIC`
glibc build with /usr/local/bin/ld pointing to ld.lld works
with
"csu: Skip ARCH_SETUP_IREL if _dl_relocate_static_pie applied IRELATIVE relocations"
and
"configure: Allow LD to be LLD 9.0.0 or above"
i.e. glibc build doesn't need the diagnostic suppression.
Comment 7 Sourceware Commits 2021-07-08 21:02:18 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=661b504df9bfb8d7c5d669091720e1dc0079c05e

commit 661b504df9bfb8d7c5d669091720e1dc0079c05e
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Jul 8 13:49:17 2021 -0700

    x86-64: Disallow PC reloc against weak undefined symbols in PIE
    
    Disallow PC relocations against weak undefined symbols in PIE since they
    can lead to non-zero address at run-time.
    
    bfd/
    
            PR ld/21782
            * elf64-x86-64.c (elf_x86_64_relocate_section): Disallow PC
            relocations against weak undefined symbols in PIE.
    
    ld/
    
            PR ld/21782
            * testsuite/ld-x86-64/pie3.d: Expect linker error.
Comment 8 Sourceware Commits 2021-07-08 21:07:26 UTC
The binutils-2_37-branch branch has been updated by H.J. Lu <hjl@sourceware.org>:

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

commit cce64d8d01ba1558f9fc93775b9d96b40a019199
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Jul 8 14:03:53 2021 -0700

    x86-64: Disallow PC reloc against weak undefined symbols in PIE
    
    Disallow PC relocations against weak undefined symbols in PIE since they
    can lead to non-zero address at run-time.
    
    bfd/
    
            PR ld/21782
            * elf64-x86-64.c (elf_x86_64_relocate_section): Disallow PC
            relocations against weak undefined symbols in PIE.
    
    ld/
    
            PR ld/21782
            * testsuite/ld-x86-64/pie3.d: Expect linker error.
    
    (cherry picked from commit 661b504df9bfb8d7c5d669091720e1dc0079c05e)