bfd/
authorAlan Modra <amodra@gmail.com>
Tue, 8 Nov 2011 13:06:03 +0000 (13:06 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 8 Nov 2011 13:06:03 +0000 (13:06 +0000)
* elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename
ha_relocs_not_using_r2 to unexpected_toc_insn.
(ok_lo_toc_insn): New function.
(ppc64_elf_edit_toc): Check insn on lo toc reloc.  Emit warning.
(ppc64_elf_relocate_section): Don't check insn on lo toc reloc here.
Handle addic on lo toc reloc.
ld/testsuite/
* ld-powerpc/powerpc.exp: Expect ld warnings for tocopt test.
* ld-powerpc/tocopt.out: New file.

bfd/ChangeLog
bfd/elf64-ppc.c
ld/testsuite/ChangeLog
ld/testsuite/ld-powerpc/powerpc.exp
ld/testsuite/ld-powerpc/tocopt.out [new file with mode: 0644]

index ac69b7b..b145c57 100644 (file)
@@ -1,3 +1,12 @@
+2011-11-08  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename
+       ha_relocs_not_using_r2 to unexpected_toc_insn.
+       (ok_lo_toc_insn): New function.
+       (ppc64_elf_edit_toc): Check insn on lo toc reloc.  Emit warning.
+       (ppc64_elf_relocate_section): Don't check insn on lo toc reloc here.
+       Handle addic on lo toc reloc.
+
 2011-11-06  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        PR ld/13387
index dfe10fa..351ebc1 100644 (file)
@@ -2614,8 +2614,9 @@ struct ppc64_elf_obj_tdata
      the reloc to be in the range -32768 to 32767.  */
   unsigned int has_small_toc_reloc : 1;
 
-  /* Set if toc/got ha relocs detected not using r2.  */
-  unsigned int ha_relocs_not_using_r2 : 1;
+  /* Set if toc/got ha relocs detected not using r2, or lo reloc
+     instruction not one we handle.  */
+  unsigned int unexpected_toc_insn : 1;
 };
 
 #define ppc64_elf_tdata(bfd) \
@@ -8016,6 +8017,32 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc.  */
+
+static bfd_boolean
+ok_lo_toc_insn (unsigned int insn)
+{
+  return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+         || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+         || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+         || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+         || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+         || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+         || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+         || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+         || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+         || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+         || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+         || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+         || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+         || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+         || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+             && (insn & 3) != 1)
+         || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+             && ((insn & 3) == 0 || (insn & 3) == 3))
+         || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
+}
+
 /* Examine all relocs referencing .toc sections in order to remove
    unused .toc entries.  */
 
@@ -8270,11 +8297,13 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                struct elf_link_hash_entry *h;
                Elf_Internal_Sym *sym;
                bfd_vma val;
+               enum {no_check, check_lo, check_ha} insn_check;
 
                r_type = ELF64_R_TYPE (rel->r_info);
                switch (r_type)
                  {
                  default:
+                   insn_check = no_check;
                    break;
 
                  case R_PPC64_GOT_TLSLD16_HA:
@@ -8283,24 +8312,49 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  case R_PPC64_GOT_DTPREL16_HA:
                  case R_PPC64_GOT16_HA:
                  case R_PPC64_TOC16_HA:
-                   {
-                     bfd_vma off = rel->r_offset & ~3;
-                     unsigned char buf[4];
-                     unsigned int insn;
+                   insn_check = check_ha;
+                   break;
 
-                     if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
-                       {
-                         free (used);
-                         goto error_ret;
-                       }
-                     insn = bfd_get_32 (ibfd, buf);
-                     if ((insn & ((0x3f << 26) | 0x1f << 16))
-                         != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
-                       ppc64_elf_tdata (ibfd)->ha_relocs_not_using_r2 = 1;
-                   }
+                 case R_PPC64_GOT_TLSLD16_LO:
+                 case R_PPC64_GOT_TLSGD16_LO:
+                 case R_PPC64_GOT_TPREL16_LO_DS:
+                 case R_PPC64_GOT_DTPREL16_LO_DS:
+                 case R_PPC64_GOT16_LO:
+                 case R_PPC64_GOT16_LO_DS:
+                 case R_PPC64_TOC16_LO:
+                 case R_PPC64_TOC16_LO_DS:
+                   insn_check = check_lo;
                    break;
                  }
 
+               if (insn_check != no_check)
+                 {
+                   bfd_vma off = rel->r_offset & ~3;
+                   unsigned char buf[4];
+                   unsigned int insn;
+
+                   if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+                     {
+                       free (used);
+                       goto error_ret;
+                     }
+                   insn = bfd_get_32 (ibfd, buf);
+                   if (insn_check == check_lo
+                       ? !ok_lo_toc_insn (insn)
+                       : ((insn & ((0x3f << 26) | 0x1f << 16))
+                          != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+                     {
+                       char str[12];
+
+                       ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+                       sprintf (str, "%#08x", insn);
+                       info->callbacks->einfo
+                         (_("%P: %H: toc optimization is not supported for"
+                            " %s instruction.\n"),
+                          ibfd, sec, rel->r_offset & ~3, str);
+                     }
+                 }
+
                switch (r_type)
                  {
                  case R_PPC64_TOC16:
@@ -13322,7 +13376,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT16_HA:
        case R_PPC64_TOC16_HA:
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
-             && !ppc64_elf_tdata (input_bfd)->ha_relocs_not_using_r2)
+             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              bfd_put_32 (input_bfd, NOP, p);
@@ -13338,33 +13392,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_LO_DS:
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
-             && !ppc64_elf_tdata (input_bfd)->ha_relocs_not_using_r2)
+             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              insn = bfd_get_32 (input_bfd, p);
-             if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
-                 || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
-                 || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
-                 || (insn & (0x3f << 26)) == 36u << 26 /* stw */
-                 || (insn & (0x3f << 26)) == 38u << 26 /* stb */
-                 || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
-                 || (insn & (0x3f << 26)) == 42u << 26 /* lha */
-                 || (insn & (0x3f << 26)) == 44u << 26 /* sth */
-                 || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
-                 || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
-                 || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
-                 || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
-                 || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
-                 || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
-                 || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
-                     && (insn & 3) != 1)
-                 || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
-                     && ((insn & 3) == 0 || (insn & 3) == 3)))
+             if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
+               {
+                 /* Transform addic to addi when we change reg.  */
+                 insn &= ~((0x3f << 26) | (0x1f << 16));
+                 insn |= (14u << 26) | (2 << 16);
+               }
+             else
                {
                  insn &= ~(0x1f << 16);
                  insn |= 2 << 16;
-                 bfd_put_32 (input_bfd, insn, p);
                }
+             bfd_put_32 (input_bfd, insn, p);
            }
          break;
        }
index 41212ea..aca734d 100644 (file)
@@ -1,3 +1,8 @@
+2011-11-08  Alan Modra  <amodra@gmail.com>
+
+       * ld-powerpc/powerpc.exp: Expect ld warnings for tocopt test.
+       * ld-powerpc/tocopt.out: New file.
+
 2011-10-25  Joern Rennecke  <joern.rennecke@embecosm.com>
 
        * ld-srec/srec.exp: xfail epiphany.
index 7f9e7fa..566272d 100644 (file)
@@ -204,7 +204,7 @@ set ppc64elftests {
     {"sym@tocbase" "-shared -melf64ppc" "-a64" {symtocbase-1.s symtocbase-2.s}
        {{objdump -dj.data symtocbase.d}} "symtocbase.so"}
     {"TOC opt" "-melf64ppc" "-a64"  {tocopt.s}
-       {{objdump -s tocopt.d}} "tocopt"}
+       {{ld tocopt.out} {objdump -s tocopt.d}} "tocopt"}
     {"TOC opt2" "-melf64ppc --defsym x=2" "-a64"  {tocopt2.s}
        {{ld tocopt2.out} {objdump -s tocopt2.d}} "tocopt2"}
     {"TOC opt3" "-melf64ppc -no-keep-memory --defsym x=2" "-a64"  {tocopt3.s}
diff --git a/ld/testsuite/ld-powerpc/tocopt.out b/ld/testsuite/ld-powerpc/tocopt.out
new file mode 100644 (file)
index 0000000..6df909f
--- /dev/null
@@ -0,0 +1,4 @@
+.*
+\(\.text\+0x14\): .* 0x3fa00000 .*
+.*
+\(\.text\+0x34\): .* 0x3fa00010 .*