R_PPC64_PCREL_OPT
authorAlan Modra <amodra@gmail.com>
Wed, 4 Sep 2019 06:00:37 +0000 (15:30 +0930)
committerAlan Modra <amodra@gmail.com>
Thu, 5 Sep 2019 04:26:20 +0000 (13:56 +0930)
The loads and stores handled in the second instruction of a sequence
marked by R_PPC64_PCREL_OPT may be a prefix instruction.  For example:
 pld ra,symbol@got@pcrel
0:
 pld rt,off(ra)
 .reloc 0b-8,R_PPC64_PCREL_OPT,(.-8)-(0b-8)
can be optimised to
 pld rt,symbol+off@pcrel
 pnop

* elf64-ppc.c (xlate_pcrel_opt): Handle prefix loads and stores
in second instruction.
(ppc64_elf_relocate_section): Likewise.

bfd/ChangeLog
bfd/elf64-ppc.c
ld/ChangeLog
ld/testsuite/ld-powerpc/pcrelopt.d
ld/testsuite/ld-powerpc/pcrelopt.s

index 319ba5a57129c80fd77256d75c0d83e54bf49a74..7f587df81afa16bd641c3a41a1ee7261bb660618 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-05  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (xlate_pcrel_opt): Handle prefix loads and stores
+       in second instruction.
+       (ppc64_elf_relocate_section): Likewise.
+
 2019-09-05  Alan Modra  <amodra@gmail.com>
 
        PR 24955
index a5bd3426ee4727f597fe7ec87f06b42221725b01..e39b6faf17b9bba73ae05b6fb5647317aa789750 100644 (file)
@@ -8282,12 +8282,31 @@ ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
 static bfd_boolean
 xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
 {
-  uint32_t insn2 = *pinsn2 >> 32;
-  uint64_t i1new;
+  uint64_t insn1 = *pinsn1;
+  uint64_t insn2 = *pinsn2;
   bfd_signed_vma off;
 
+  if ((insn2 & (63ULL << 58)) == 1ULL << 58)
+    {
+      /* Check that regs match.  */
+      if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
+       return FALSE;
+
+      /* P8LS or PMLS form, non-pcrel.  */
+      if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58))
+       return FALSE;
+
+      *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52);
+      *pinsn2 = PNOP;
+      off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff);
+      *poff = (off ^ 0x200000000ULL) - 0x200000000ULL;
+      return TRUE;
+    }
+
+  insn2 >>= 32;
+
   /* Check that regs match.  */
-  if (((insn2 >> 16) & 31) != ((*pinsn1 >> 21) & 31))
+  if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
     return FALSE;
 
   switch ((insn2 >> 26) & 63)
@@ -8308,7 +8327,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
     case 54: /* stfd */
       /* These are the PMLS cases, where we just need to tack a prefix
         on the insn.  */
-      i1new = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
+      insn1 = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
               | (insn2 & ((63ULL << 26) | (31ULL << 21))));
       off = insn2 & 0xffff;
       break;
@@ -8316,7 +8335,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
     case 58: /* lwa, ld */
       if ((insn2 & 1) != 0)
        return FALSE;
-      i1new = ((1ULL << 58) | (1ULL << 52)
+      insn1 = ((1ULL << 58) | (1ULL << 52)
               | (insn2 & 2 ? 41ULL << 26 : 57ULL << 26)
               | (insn2 & (31ULL << 21)));
       off = insn2 & 0xfffc;
@@ -8325,7 +8344,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
     case 57: /* lxsd, lxssp */
       if ((insn2 & 3) < 2)
        return FALSE;
-      i1new = ((1ULL << 58) | (1ULL << 52)
+      insn1 = ((1ULL << 58) | (1ULL << 52)
               | ((40ULL | (insn2 & 3)) << 26)
               | (insn2 & (31ULL << 21)));
       off = insn2 & 0xfffc;
@@ -8336,14 +8355,14 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
        return FALSE;
       else if ((insn2 & 3) >= 2)
        {
-         i1new = ((1ULL << 58) | (1ULL << 52)
+         insn1 = ((1ULL << 58) | (1ULL << 52)
                   | ((44ULL | (insn2 & 3)) << 26)
                   | (insn2 & (31ULL << 21)));
          off = insn2 & 0xfffc;
        }
       else
        {
-         i1new = ((1ULL << 58) | (1ULL << 52)
+         insn1 = ((1ULL << 58) | (1ULL << 52)
                   | ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26)
                   | (insn2 & (31ULL << 21)));
          off = insn2 & 0xfff0;
@@ -8351,7 +8370,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
       break;
 
     case 56: /* lq */
-      i1new = ((1ULL << 58) | (1ULL << 52)
+      insn1 = ((1ULL << 58) | (1ULL << 52)
               | (insn2 & ((63ULL << 26) | (31ULL << 21))));
       off = insn2 & 0xffff;
       break;
@@ -8359,14 +8378,14 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
     case 62: /* std, stq */
       if ((insn2 & 1) != 0)
        return FALSE;
-      i1new = ((1ULL << 58) | (1ULL << 52)
+      insn1 = ((1ULL << 58) | (1ULL << 52)
               | ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26)
               | (insn2 & (31ULL << 21)));
       off = insn2 & 0xfffc;
       break;
     }
 
-  *pinsn1 = i1new;
+  *pinsn1 = insn1;
   *pinsn2 = (uint64_t) NOP << 32;
   *poff = (off ^ 0x8000) - 0x8000;
   return TRUE;
@@ -15413,7 +15432,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          pinsn2 = bfd_get_32 (input_bfd, contents + off2);
                          pinsn2 <<= 32;
                          if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
-                           break;
+                           {
+                             if (off2 + 8 > input_section->size)
+                               break;
+                             pinsn2 |= bfd_get_32 (input_bfd,
+                                                   contents + off2 + 4);
+                           }
                          if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
                            {
                              addend += addend_off;
@@ -15424,6 +15448,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                          contents + offset + 4);
                              bfd_put_32 (input_bfd, pinsn2 >> 32,
                                          contents + off2);
+                             if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
+                               bfd_put_32 (input_bfd, pinsn2,
+                                           contents + off2 + 4);
                            }
                        }
                    }
index b654eb9d3638fb4bd5371b92309c2ce4291825ab..0da9e2542da2c5fa8e136f453234855f5cc7ed40 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-05  Alan Modra  <amodra@gmail.com>
+
+       * testsuite/ld-powerpc/pcrelopt.s,
+       * testsuite/ld-powerpc/pcrelopt.d: Test offset and prefix in
+       second instruction.
+
 2019-08-29  Alan Modra  <amodra@gmail.com>
 
        PR ld/24406
index 18fdb95abffd4415ec35b31923e494abe4482c9c..aeaa0cdb5d9ee70c12d543e7e411608738d8c211 100644 (file)
@@ -80,10 +80,17 @@ Disassembly of section \.text:
 .*:    (04 10 00 01|01 00 10 04)       pstxv   vs0,66028
 .*:    (d8 00 01 ec|ec 01 00 d8) 
 .*:    (60 00 00 00|00 00 00 60)       nop
-.*:    (04 10 00 01|01 00 10 04)       pld     r9,66008
-.*:    (e5 20 01 d8|d8 01 20 e5
-.*:    (e8 09 00 00|00 00 09 e8)       ld      r0,0\(r9\)
+.*:    (06 10 00 01|01 00 10 06)       plbz    r3,70676
+.*:    (88 60 14 14|14 14 60 88
+.*:    (60 00 00 00|00 00 00 60)       nop
 .*:    (60 00 00 00|00 00 00 60)       nop
-.*:    (06 10 00 01|01 00 10 06)       pla     r7,66000
-.*:    (38 e0 01 d0|d0 01 e0 38) 
+.*:    (04 10 12 35|35 12 10 04)       plq     r4,305485896
+.*:    (e0 80 58 48|48 58 80 e0) 
+.*:    (07 00 00 00|00 00 00 07)       pnop
+.*:    (00 00 00 00|00 00 00 00) 
+.*:    (04 10 00 01|01 00 10 04)       pld     r9,65976
+.*:    (e5 20 01 b8|b8 01 20 e5) 
+.*:    (e8 09 00 00|00 00 09 e8)       ld      r0,0\(r9\)
+.*:    (06 10 00 01|01 00 10 06)       pla     r7,65972
+.*:    (38 e0 01 b4|b4 01 e0 38) 
 .*:    (88 c7 00 00|00 00 c7 88)       lbz     r6,0\(r7\)
index 78b0f51f733d2b5ac6683623042ce8e66a60b409..715a52b5f7ba0f959886f533cb17092279247504 100644 (file)
@@ -103,6 +103,18 @@ _start:
                .reloc .-8,R_PPC64_PCREL_OPT,0f-(.-8)
 0:     stxv 0,0(9)
 
+#offsets are allowed too
+       pld 9,sym@got@pcrel
+0:
+       lbz 3,0x1234(9)
+       .reloc 0b-8,R_PPC64_PCREL_OPT,(.-4)-(0b-8)
+
+#and prefix insns as the second insn
+       pld 9,sym@got@pcrel
+0:
+       plq 4,0x12345678(9)
+       .reloc 0b-8,R_PPC64_PCREL_OPT,(.-8)-(0b-8)
+
 # This should not optimize
        .extern i
        .type i,@object