<div dir="ltr">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:<div><br></div><div>commit fa40fbe484954c560ab1c0ff4bc1b2eeb1511344<br>Author: Alan Modra <<a href="mailto:amodra@gmail.com">amodra@gmail.com</a>><br>Date:   Fri Oct 9 16:56:33 2020 +1030<br><br>    [GOLD] Power10 segv due to wild r2<br>    <br>    Calling non-pcrel functions from pcrel code requires a stub to set up<br>    r2.  Gold created the stub, but an "optimisation" made the stub jump<br>    to the function local entry, ie. r2 was not initialised.<br>    <br>    This patch fixes that long branch stub problem, and another that might<br>    occur for plt call stubs to local functions.<br>    <br>    bfd/<br>            * elf64-ppc.c (write_plt_relocs_for_local_syms): Don't do local<br>            entry offset optimisation.<br>    gold/<br>            * powerpc.cc (Powerpc_relobj::do_relocate_sections): Don't do<br>            local entry offset optimisation for lplt_section.<br>            (Target_powerpc::Branch_info::make_stub): Don't add local<br>            entry offset to long branch dest passed to<br>            add_long_branch_entry.  Do pass st_other bits.<br>            (Stub_table::Branch_stub_ent): Add "other_" field.<br>            (Stub_table::add_long_branch_entry): Add "other" param, and<br>            save.<br>            (Stub_table::branch_stub_size): Adjust long branch offset.<br>            (Stub_table::do_write): Likewise.<br>            (Target_powerpc::Relocate::relocate): Likewise.<br></div><div><br></div><div>In particular, it's this bit:</div><div><br></div><div>            (Target_powerpc::Branch_info::make_stub): Don't add local<br>            entry offset to long branch dest passed to<br>            add_long_branch_entry.  Do pass st_other bits.<br></div><div><br></div><div>Some background, if anyone cares:</div><div><br></div><div>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:</div><div><br></div><div>    103fa688:   21 91 c0 4b     bl      100037a8 <_init+0x8><br></div><div><br></div><div>(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:</div><div><br></div><div>(gdb) disassemble 0x14dcb998<br>Dump of assembler code for function 00000001.long_branch.10004b48:<br>   0x0000000014dcb990 <+0>: addis   r12,r2,-1<br>   0x0000000014dcb994 <+4>: ld      r12,32216(r12)<br>   0x0000000014dcb998 <+8>:  mtctr   r12<br>   0x0000000014dcb99c <+12>:      bctr<br></div><div><br></div><div>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:</div><div><br></div><div>   0x0000000014dc8b08 <+72>:    bl      0x14dcb998 <00000001.long_branch.10004b48+8><br></div><div><br></div><div>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.</div><div><br></div></div>