https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119609

            Bug ID: 119609
           Summary: [powerpc-elf] load_toc_v4_pic_si may clobber r12 and
                    crt
           Product: gcc
           Version: 14.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: aoliva at gcc dot gnu.org
  Target Milestone: ---

A buggy linker script placed .got too far from .text and triggered a latent
bug.

A small leaf function that needed the got register to compute the address of a
global symbol (say intptr_t foo (void) { return (intptr_t)foo; }) ended up with
the following got setup sequence:

        mflr 12
        .cfi_register 65, 12
        bl _GLOBAL_OFFSET_TABLE_@local-4
        mflr 30
        mtlr 12
        .cfi_restore 65

it is rs6000_emit_prologue, under save_LR_around_toc_setup, that chooses r12:

      /* If emit_load_toc_table will use the link register, we need to save
         it.  We use R12 for this purpose because emit_load_toc_table
         can use register 0.

The problem is that, when the bl above needs relaxation, the relaxation stubs
introduced by the linker, whether for shared or static linking, always clobber
r12 and crt, and in the shared case, r0 as well:

/* Relaxation trampolines.  r12 is available for clobbering (r11, is
   used for some functions that are allowed to break the ABI).  */
static const int shared_stub_entry[] =
  { 
    0x7c0802a6, /* mflr 0 */
    0x429f0005, /* bcl 20, 31, .Lxxx */
    0x7d8802a6, /* mflr 12 */
    0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */
    0x398c0000, /* addi 12, 12, (xxx-.Lxxx)@l */
    0x7c0803a6, /* mtlr 0 */
    0x7d8903a6, /* mtctr 12 */
    0x4e800420, /* bctr */
  };

static const int stub_entry[] =
  { 
    0x3d800000, /* lis 12,xxx@ha */
    0x398c0000, /* addi 12,12,xxx@l */
    0x7d8903a6, /* mtctr 12 */
    0x4e800420, /* bctr */
  };

Of course adding clobbers to load_toc_v4_pic_si is not enough, the lr
save/restore needs to choose a different register too.

In the end, fixing the linker script worked around the problem, so I'm not sure
I can justify spending further time on this fix, but hopefully I'll be able to
return to it at some point.  Anyway, I'm filing this in case someone else feels
like beating me to the fix.

Reply via email to