Bug#973623:

Michael Hudson-Doyle michael.hudson at canonical.com
Tue Nov 3 01:21:47 GMT 2020


I think this is a gold bug, and even better I think it is a gold bug that
was fixed already, in this commit from a few weeks back:

commit fa40fbe484954c560ab1c0ff4bc1b2eeb1511344
Author: Alan Modra <amodra at gmail.com>
Date:   Fri Oct 9 16:56:33 2020 +1030

    [GOLD] Power10 segv due to wild r2

    Calling non-pcrel functions from pcrel code requires a stub to set up
    r2.  Gold created the stub, but an "optimisation" made the stub jump
    to the function local entry, ie. r2 was not initialised.

    This patch fixes that long branch stub problem, and another that might
    occur for plt call stubs to local functions.

    bfd/
            * elf64-ppc.c (write_plt_relocs_for_local_syms): Don't do local
            entry offset optimisation.
    gold/
            * powerpc.cc (Powerpc_relobj::do_relocate_sections): Don't do
            local entry offset optimisation for lplt_section.
            (Target_powerpc::Branch_info::make_stub): Don't add local
            entry offset to long branch dest passed to
            add_long_branch_entry.  Do pass st_other bits.
            (Stub_table::Branch_stub_ent): Add "other_" field.
            (Stub_table::add_long_branch_entry): Add "other" param, and
            save.
            (Stub_table::branch_stub_size): Adjust long branch offset.
            (Stub_table::do_write): Likewise.
            (Target_powerpc::Relocate::relocate): Likewise.

In particular, it's this bit:

            (Target_powerpc::Branch_info::make_stub): Don't add local
            entry offset to long branch dest passed to
            add_long_branch_entry.  Do pass st_other bits.

Some background, if anyone cares:

Most functions on ppc64 have two entry points, a global and local entry
point. The global entry point is the one that is called from other shared
objects, derives the "module TOC pointer" from r12 (the abi mandates that
calls via a function pointer must have that pointer in r12), and stores it
in r2. The local entry point assumes that r2 is already set up (and does
not care about what is in r12), so most local calls look like this:

    103fa688:   21 91 c0 4b     bl      100037a8 <_init+0x8>

(this is from __libc_csu_init from a trivial haskell executable which does
not crash). But! the displacement field for the bl instruction in the ppc64
ISA is "only" 26 bits. When the target function is too far away, the linker
generates a stub, like this:

(gdb) disassemble 0x14dcb998
Dump of assembler code for function 00000001.long_branch.10004b48:
   0x0000000014dcb990 <+0>: addis   r12,r2,-1
   0x0000000014dcb994 <+4>: ld      r12,32216(r12)
   0x0000000014dcb998 <+8>: mtctr   r12
   0x0000000014dcb99c <+12>: bctr

This derives the address of the target function from r2, puts it in r12 per
abi rules and calls it. But the call to this stub in __libc_csu_init from a
broken haskell executable looks like this:

   0x0000000014dc8b08 <+72>: bl      0x14dcb998
<00000001.long_branch.10004b48+8>

i.e. it's jumping into the middle of the stub, and so jumps straight to
r12, which contains the address of __libc_csu_init itself at the moment --
and so we just recurse infinitely until we crash.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-haskell-maintainers/attachments/20201103/78b364d3/attachment-0001.html>


More information about the Pkg-haskell-maintainers mailing list