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

            Bug ID: 79439
           Summary: Missing nop instruction after recursive call corrupts
                    TOC register
           Product: gcc
           Version: 6.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: fw at gcc dot gnu.org
  Target Milestone: ---
            Target: ppc64le-redhat-linux

Consider this test case:

int f (void);

void
g (void)
{
}

void
rec (int a)
{
  if (f ())
    rec (a + 1);
  rec (a);
  g ();
}

GCC 6.3.1 generates the following code on ppc64le-redhat-linux (Fedora 25):

rec:
.LCF1:
0:      addis 2,12,.TOC.-.LCF1@ha
        addi 2,2,.TOC.-.LCF1@l
        .localentry     rec,.-rec
        mflr 0
        std 31,-8(1)
        mr 31,3
        std 0,16(1)
        stdu 1,-48(1)
        bl f
        nop
        cmpdi 7,3,0
        beq 7,.L3
        addi 3,31,1
        extsw 3,3
        bl rec
.L3:
        mr 3,31
        bl rec
        bl g
        nop
        addi 1,1,48
        ld 0,16(1)
        ld 31,-8(1)
        mtlr 0
        blr
        .long 0
        .byte 0,0,0,1,128,1,0,0


That is, there is no nop instruction the after the “bl rec” instructions.  The
ELF v2 ABI requires the presence of this instruction, so that the static linker
can replace it with a load of the saved TOC pointer to restore the original
value of the TOC pointer register.  

Apparently, GCC assumes that the call is always to a function in the same
module, so the TOC pointer restore is never needed.  But “rec” can be
interposed from another translation unit and the original function definition
can be access through dlsym and executed, so this assumption is incorrect.  The
missing TOC pointer restore means that the PLT stubs supplied by the static
linker will not work, and subsequent function calls can crash.

This was originally reported as a glibc bug:

  <https://sourceware.org/bugzilla/show_bug.cgi?id=21116>

The test case is LAPACK, which is apparently written in Fortran, but I expect
that this is a target issue which exists independent of the front end.

Reply via email to