Created attachment 12203 [details] libshared.so This script produces a ./main executable which crashes when run: cat >like-pthread.c <<EOF void implementation (void) { } EOF gcc -fPIC -shared -o liblike-pthread.so like-pthread.c -Wl,-z,now cat >like-dl.c <<EOF extern void implementation (void) __attribute__ ((weak)); void use_implementation (void) { if (implementation != 0) implementation (); } EOF gcc -fPIC -shared -o liblike-dl.so like-dl.c -Wl,-z,now cat >shared.c <<EOF extern void use_implementation (void); extern void _exit (int); void call_dlopen (void) { use_implementation (); _exit (0); } EOF cat >main.s <<EOF .section .rodata ptr: .quad alias .weakref alias, implementation .section ".opd","aw" .align 3 .globl main main: .quad .L.main,.TOC.@tocbase .text .type main, @function .L.main: bl call_dlopen nop EOF gcc -fPIC -shared -o libshared.so shared.c -Wl,--no-as-needed -L. -llike-dl -llike-pthread gcc -Wl,-rpath,. -o main main.s -Wl,--no-as-needed -L. -lshared It reproduces with binutils 2.27 and the current master branch in Git (at commit 7a6bf3becbe3e0ce47d2681edcfe7adcb67fe4e2). GDB says this: Program received signal SIGSEGV, Segmentation fault. 0x0000000000000000 in ?? () (gdb) bt #0 0x0000000000000000 in ?? () #1 0x00003fffb7d008c8 in use_implementation () from ./liblike-dl.so #2 0x00003fffb7f50918 in call_dlopen () from ./libshared.so #3 0x0000000010000784 in main () The construct in use_implementation was previously discussed here: <https://www.sourceware.org/ml/gnu-gabi/2016-q1/msg00004.html> This crash arises when current glibc is built with --enable-bind-now (see the downstream report; our 2.17 build includes the --enable-bind-now changes in glibc master).
Created attachment 12204 [details] liblike-dl.so
Created attachment 12205 [details] liblike-pthread.so
The trigger for this problem is an initialized function pointer in a read-only section, the function being defined in a shared library. .section .rodata ptr: .quad alias .weakref alias, implementation That generates a .dynbss copy and copy reloc via linker code supposed to work around bugs in very old versions of gcc. The work-around should have reported an error if (h->plt.plist != NULL) { /* We should never get here, but unfortunately there are versions of gcc out there that improperly (for this ABI) put initialized function pointers, vtable refs and suchlike in read-only sections. Allow them to proceed, but warn that this might break at runtime. */ info->callbacks->einfo (_("%P: copy reloc against `%T' requires lazy plt linking; " "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"), h->root.root.string); } but doesn't due to a lack of a call to "implementation" in the executable. (plt.plist is NULL). That's a linker bug. The warning is relevant even when there is no call in the executable. So we have this .dynbss copy of the "implementation" function descriptor in the executable: 000000001001fc08 0000000800000013 R_PPC64_COPY 000000001001fc08 implementation + 0 8: 000000001001fc08 40 FUNC GLOBAL DEFAULT 18 implementation Notice that the size (40) is incorrect for a function descriptor. That's because gcc puts the text size of the function on the symbol. But that means the .dynbss copy is the wrong size too, a linker and glibc bug if we are to support .dynbss copies of function descriptors with versions of gcc since 2004 when dot-symbols were removed. (With dot-symbols, the size of the "implementation symbol is the size of the function descriptor with the size of ".implementation" being the text size.) Anyway, a size larger than 16 is OK for copying the descriptor and "works" just as well for this testcase as if we copied the descriptor. We just get some more of .opd copied from the library defining "implementation". The segfault happens because the PLT slot in liblike-dl.so for "implementation" is initialized from the function descriptor for "implementation", which is now the copy in main. Unfortunately that initialization happens before "main" is processed to initialize the copy, resulting in the PLT slot being set to zeros.
The master branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e1c6cf618cbeebbafd34afc5ee921fcbf7061bfa commit e1c6cf618cbeebbafd34afc5ee921fcbf7061bfa Author: Alan Modra <amodra@gmail.com> Date: Tue Jan 14 20:45:53 2020 +1030 PR25384, PowerPC64 ELFv1 copy relocs against function symbols Function symbols of course don't normally want .dynbss copies but with some old versions of gcc they are needed to copy the function descriptor. This patch restricts the cases where they are useful to compilers using dot-symbols, and enables the warning regardless of whether a PLT entry is emitted in the executable. PLTs in shared libraries are affected by a .dynbss copy in the executable. bfd/ PR 25384 * elf64-ppc.c (ELIMINATE_COPY_RELOCS): Update comment. (ppc64_elf_adjust_dynamic_symbol): Don't allow .dynbss copies of function symbols unless dot symbols are present. Do warn whenever one is created, regardles of whether a PLT entry is also emitted for the function symbol. ld/ * testsuite/ld-powerpc/ambiguousv1b.d: Adjust expected output. * testsuite/ld-powerpc/funref.s: Align func_tab. * testsuite/ld-powerpc/funref2.s: Likewise. * testsuite/ld-powerpc/funv1.s: Add dot symbols.
Fixed. You'll now get DT_TEXTREL and a dynamic reloc instead of a .dynbss copy.
The binutils-2_33-branch branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=02efd171de60180efa8f77e311cd1382a52553c6 commit 02efd171de60180efa8f77e311cd1382a52553c6 Author: Alan Modra <amodra@gmail.com> Date: Tue Jan 14 20:45:53 2020 +1030 PR25384, PowerPC64 ELFv1 copy relocs against function symbols Function symbols of course don't normally want .dynbss copies but with some old versions of gcc they are needed to copy the function descriptor. This patch restricts the cases where they are useful to compilers using dot-symbols, and enables the warning regardless of whether a PLT entry is emitted in the executable. PLTs in shared libraries are affected by a .dynbss copy in the executable. bfd/ PR 25384 * elf64-ppc.c (ELIMINATE_COPY_RELOCS): Update comment. (ppc64_elf_adjust_dynamic_symbol): Don't allow .dynbss copies of function symbols unless dot symbols are present. Do warn whenever one is created, regardles of whether a PLT entry is also emitted for the function symbol. ld/ * testsuite/ld-powerpc/ambiguousv1b.d: Adjust expected output. * testsuite/ld-powerpc/funref.s: Align func_tab. * testsuite/ld-powerpc/funref2.s: Likewise. * testsuite/ld-powerpc/funv1.s: Add dot symbols. (cherry picked from commit e1c6cf618cbeebbafd34afc5ee921fcbf7061bfa)
The binutils-2_32-branch branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f5deb4103e0cec3912c304d7c08277aadab09e5c commit f5deb4103e0cec3912c304d7c08277aadab09e5c Author: Alan Modra <amodra@gmail.com> Date: Tue Jan 14 20:45:53 2020 +1030 PR25384, PowerPC64 ELFv1 copy relocs against function symbols Function symbols of course don't normally want .dynbss copies but with some old versions of gcc they are needed to copy the function descriptor. This patch restricts the cases where they are useful to compilers using dot-symbols, and enables the warning regardless of whether a PLT entry is emitted in the executable. PLTs in shared libraries are affected by a .dynbss copy in the executable. bfd/ PR 25384 * elf64-ppc.c (ELIMINATE_COPY_RELOCS): Update comment. (ppc64_elf_adjust_dynamic_symbol): Don't allow .dynbss copies of function symbols unless dot symbols are present. Do warn whenever one is created, regardles of whether a PLT entry is also emitted for the function symbol. ld/ * testsuite/ld-powerpc/ambiguousv1b.d: Adjust expected output. * testsuite/ld-powerpc/funref.s: Align func_tab. * testsuite/ld-powerpc/funref2.s: Likewise. * testsuite/ld-powerpc/funv1.s: Add dot symbols. (cherry picked from commit e1c6cf618cbeebbafd34afc5ee921fcbf7061bfa)
I believe later GCC (I tried 7) uses .data.relro with -O0 and the __pthread_key_create-based single thread detection, not .rodata. This means that the current toolchain is consistent and does not produce text relocations.