Bug 22592 - dyn_reloc count error for sparc PIE
Summary: dyn_reloc count error for sparc PIE
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.29
: P2 normal
Target Milestone: 2.31
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-12-12 10:48 UTC by Rolf Eike Beer
Modified: 2018-03-31 12:36 UTC (History)
6 users (show)

See Also:
Host: sparc-unknown-linux-gnu
Target: sparc-unknown-linux-gnu
Build:
Last reconfirmed: 2017-12-12 00:00:00


Attachments
object files and shared libraries (808.38 KB, application/x-xz)
2017-12-12 10:48 UTC, Rolf Eike Beer
Details
Proposed patch (835 bytes, patch)
2017-12-14 09:35 UTC, Jessica Clarke
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Rolf Eike Beer 2017-12-12 10:48:28 UTC
Created attachment 10682 [details]
object files and shared libraries

The compiler is gcc 6.4.0. Switching to binutils 2.28.1 makes things work. Commit a9d44aad42 is applied.

castor /var/tmp/portage/net-fs/cifs-utils-6.4/work/cifs-utils-6.4 #  sparc-
unknown-linux-gnu-gcc -Wall -Wextra -D_FORTIFY_SOURCE=2 -fpie -pie -Wl,-
z,relro,-z,now -O2 -mcpu=niagara2 -pipe  -Wl,-O1 -Wl,--as-needed -o 
cifs.upcall cifs.upcall.o data_blob.o asn1.o spnego.o -ltalloc -lkeyutils -
lkrb5
collect2: fatal error: ld terminated with signal 11 [Segmentation fault]
compilation terminated.
castor /var/tmp/portage/net-fs/cifs-utils-6.4/work/cifs-utils-6.4 #  sparc-
unknown-linux-gnu-gcc -Wall -Wextra -D_FORTIFY_SOURCE=2 -fpie -Wl,-z,relro,-
z,now -O2 -mcpu=niagara2 -pipe  -Wl,-O1 -Wl,--as-needed -o cifs.upcall 
cifs.upcall.o data_blob.o asn1.o spnego.o -ltalloc -lkeyutils -lkrb5
castor /var/tmp/portage/net-fs/cifs-utils-6.4/work/cifs-utils-6.4 #

(gdb) bt
#0  0xf7d8d4e4 in free () from /lib/libc.so.6
#1  0xf7f89f3c in objalloc_free () from /usr/lib/binutils/sparc-unknown-linux-
gnu/2.29.1/libbfd-2.29.1.so
#2  0xf7f00ea4 in  () from /usr/lib/binutils/sparc-unknown-linux-gnu/2.29.1/
libbfd-2.29.1.so

The final commandline is:

/usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/../../../../sparc-unknown-linux-
gnu/bin/ld -plugin-opt=/usr/libexec/gcc/sparc-unknown-linux-gnu/6.4.0/lto-
wrapper -plugin-opt=-fresolution=/tmp/ccHxes2d.res -plugin-opt=-pass-through=-
lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-
opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --eh-frame-hdr -m 
elf32_sparc -dynamic-linker /lib/ld-linux.so.2 -relax -pie -o cifs.upcall /
usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/../../../../lib/Scrt1.o /usr/lib/
gcc/sparc-unknown-linux-gnu/6.4.0/../../../../lib/crti.o /usr/lib/gcc/sparc-
unknown-linux-gnu/6.4.0/crtbeginS.o -L/usr/lib/gcc/sparc-unknown-linux-gnu/
6.4.0 -L/usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/../../../../sparc-unknown-
linux-gnu/lib/../lib -L/usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/../../../../
lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/sparc-unknown-linux-gnu/
6.4.0/../../../../sparc-unknown-linux-gnu/lib -L/usr/lib/gcc/sparc-unknown-
linux-gnu/6.4.0/../../.. -z relro -z now -O1 --as-needed cifs.upcall.o 
data_blob.o asn1.o spnego.o -ltalloc -lkeyutils -lkrb5 -lgcc --as-needed -
lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/
gcc/sparc-unknown-linux-gnu/6.4.0/crtendS.o /usr/lib/gcc/sparc-unknown-linux-
gnu/6.4.0/../../../../lib/crtn.o

The lto-plugin part is irrelevant, the crash happens also without it. Again, removing "-pie" fixes it.
Comment 1 Alan Modra 2017-12-12 23:50:52 UTC
/home/alan/build/gas/sparc-linux/ld/ld-new: warning: libk5crypto.so.3, needed by usr/lib/libkrb5.so.3.3, not found (try using -rpath or -rpath-link)
/home/alan/build/gas/sparc-linux/ld/ld-new: warning: libcom_err.so.2, needed by usr/lib/libkrb5.so.3.3, not found (try using -rpath or -rpath-link)
/home/alan/build/gas/sparc-linux/ld/ld-new: warning: libkrb5support.so.0, needed by usr/lib/libkrb5.so.3.3, not found (try using -rpath or -rpath-link)
/home/alan/build/gas/sparc-linux/ld/ld-new: warning: libresolv.so.2, needed by usr/lib/libkrb5.so.3.3, not found (try using -rpath or -rpath-link)
usr/lib/libkrb5.so.3.3: undefined reference to `k5_get_error@krb5support_0_MIT'
usr/lib/libkrb5.so.3.3: undefined reference to `krb5_c_is_keyed_cksum@k5crypto_3_MIT'
[snip] lots more undefined reference errors.

Hmm, OK, let's try with the following

~/build/gas/sparc-linux/ld/ld-new --eh-frame-hdr -m elf32_sparc -dynamic-linker /lib/ld-linux.so.2 -relax -pie -o cifs.upcall usr/lib/Scrt1.o usr/lib/crti.o usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/crtbeginS.o -z relro -z now -O1 --as-needed cifs.upcall.o data_blob.o asn1.o spnego.o usr/lib/libtalloc.so.2.1.9 lib/libkeyutils.so.1 usr/lib/libkrb5.so.3.3 usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/libgcc.a --as-needed usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/libgcc_s.so.1 lib/libc.so.6 usr/lib/libc_nonshared.a lib/ld-linux.so.2 usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/libgcc.a usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/libgcc_s.so.1 --no-as-needed usr/lib/gcc/sparc-unknown-linux-gnu/6.4.0/crtendS.o usr/lib/crtn.o --unresolved-symbols=ignore-all

and the link succeeds.  Running the above under valgrind shows there is a problem.

==6987== Invalid write of size 1
==6987==    at 0x42FD13: bfd_putb32 (libbfd.c:690)
==6987==    by 0x4455AD: bfd_elf32_swap_reloca_out (elfcode.h:436)
==6987==    by 0x443FBC: sparc_elf_append_rela (elfxx-sparc.c:754)
==6987==    by 0x443FBC: _bfd_sparc_elf_finish_dynamic_symbol (elfxx-sparc.c:4541)
==6987==    by 0x45B3D8: elf_link_output_extsym (elflink.c:9826)
==6987==    by 0x42F2F0: bfd_hash_traverse (hash.c:656)
==6987==    by 0x46A132: bfd_elf_final_link (elflink.c:12196)
==6987==    by 0x41862D: ldwrite (ldwrite.c:581)
==6987==    by 0x4038A1: main (ldmain.c:448)
==6987==  Address 0x5e7f323 is 3 bytes after a block of size 1,744 alloc'd
==6987==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6987==    by 0x4B1F3C: _objalloc_alloc (objalloc.c:143)
==6987==    by 0x4347E0: bfd_alloc (opncls.c:949)
==6987==    by 0x434D2D: bfd_zalloc (opncls.c:998)
==6987==    by 0x4409E8: _bfd_sparc_elf_size_dynamic_sections (elfxx-sparc.c:2681)
==6987==    by 0x46434F: bfd_elf_size_dynamic_sections (elflink.c:6829)
==6987==    by 0x420F4F: gldelf32_sparc_before_allocation (eelf32_sparc.c:1296)
==6987==    by 0x4148FB: lang_process (ldlang.c:7378)
==6987==    by 0x403846: main (ldmain.c:432)

The error is repeated for offsets from 0 to 11 after the 1744 block.  So we have a dynamic reloc being written past the end of the alloc'd buffer.  It's a GOT reloc, thus there is an error in counting (or output of) GOT relocs.  I don't intend to track down exactly where the sparc backend goes wrong, but the above analysis ought to help someone else do that.
Comment 2 Alan Modra 2017-12-13 22:20:57 UTC
It will be git commit ec1acaba
https://sourceware.org/ml/binutils/2017-06/msg00368.html

That patch output more dynamic relocs without adding to elf.srelgot->size
Comment 3 Jessica Clarke 2017-12-14 09:35:52 UTC
Created attachment 10684 [details]
Proposed patch

I debugged this a few months ago as we were occasionally seeing it in Debian but never sent this upstream. The problem is because allocate_dynrelocs doesn't allocate enough GOT slots for PIC code, which is fixed by the second hunk of this patch. The other two hunks are cleanups which add other edge cases handled by other architectures but not SPARC.
Comment 4 Jessica Clarke 2017-12-14 09:44:14 UTC
(In reply to James Clarke from comment #3)
> Created attachment 10684 [details]
> Proposed patch
> 
> I debugged this a few months ago as we were occasionally seeing it in Debian
> but never sent this upstream. The problem is because allocate_dynrelocs
> doesn't allocate enough GOT slots for PIC code, which is fixed by the second
> hunk of this patch. The other two hunks are cleanups which add other edge
> cases handled by other architectures but not SPARC.

The only problem I've seen with this patch is that it now over-allocates relocations for the GOT. gdop_relative_offset_ok is only used after the GOT has been allocated, so any slots which are for objects "near" the GOT will be unused and end up as R_SPARC_NONE's padding the end of the GOT. For sparc32 we could add extra checks in allocate_dynrelocs to precisely determine whether gdop_relative_offset_ok will return TRUE for that symbol (as the entire address space is reachable with a 32-bit offset from the GOT), but for sparc64 we can't in general know if a symbol will be reachable or not that early.
Comment 5 Rolf Eike Beer 2017-12-18 08:38:49 UTC
I can confirm that the crash seems to go away when I use this patch.
Comment 6 H.J. Lu 2018-02-11 12:57:27 UTC
Please try master branch.  This may have been fixed by

commit a8735c82b8519d8b18915765ca983fc07154a17d
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Sat Feb 10 02:30:25 2018 +0100

    Fix GOT relocation overflow on SPARC.


commit c20c30f615756ddfccc4bb75c65ccfc1a399466e
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Tue Feb 6 18:15:56 2018 +0100

    Fix PR ld/22263 on SPARC.
    
    This is -fpie -pie generating dynamic relocations in the text section,
    simply because no TLS transitions are applied in PIE mode.  The meat
    of the patch is to turn calls to bfd_link_pic (info) in TLS-related code
    into !bfd_link_executable (info) and there are quite a lot of them..
Comment 7 Eric Botcazou 2018-02-11 15:20:04 UTC
Fixed yesterday on all branches (2.29, 2.30 and 2.31):

commit 9ff0c7631fb9674ab99a230d9432b782a9e93be8
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Sat Feb 10 02:54:58 2018 +0100

    Fix GOT relocation overflow on SPARC.
Comment 8 Eric Botcazou 2018-02-11 15:38:55 UTC
> The only problem I've seen with this patch is that it now over-allocates
> relocations for the GOT.

We generate the same number of GOT relocations as 2.28 and below though.