daily update
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index c1c5e6bb85141bf59b4efa5e699cea2ad128ad07..c55f3e6396d068dac3745267f2b6e3fc7fb2ee45 100644 (file)
@@ -9,7 +9,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
+
 /* The 64-bit PowerPC ELF ABI may be found at
    http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and
    http://www.linuxbase.org/spec/ELF/ppc64/spec/book1.html  */
 
+#include "sysdep.h"
 #include <stdarg.h>
 #include "bfd.h"
-#include "sysdep.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
@@ -77,6 +78,7 @@ static bfd_vma opd_entry_value
 
 #define bfd_elf64_mkobject                   ppc64_elf_mkobject
 #define bfd_elf64_bfd_reloc_type_lookup              ppc64_elf_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup
 #define bfd_elf64_bfd_merge_private_bfd_data  ppc64_elf_merge_private_bfd_data
 #define bfd_elf64_new_section_hook           ppc64_elf_new_section_hook
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
@@ -129,21 +131,25 @@ static bfd_vma opd_entry_value
 
 /* .plt call stub instructions.  The normal stub is like this, but
    sometimes the .plt entry crosses a 64k boundary and we need to
-   insert an addis to adjust r12.  */
+   insert an addi to adjust r12.  */
 #define PLT_CALL_STUB_SIZE (7*4)
 #define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha     */
 #define STD_R2_40R1    0xf8410028      /* std   %r2,40(%r1)         */
 #define LD_R11_0R12    0xe96c0000      /* ld    %r11,xxx+0@l(%r12)  */
-#define LD_R2_0R12     0xe84c0000      /* ld    %r2,xxx+8@l(%r12)   */
 #define MTCTR_R11      0x7d6903a6      /* mtctr %r11                */
+#define LD_R2_0R12     0xe84c0000      /* ld    %r2,xxx+8@l(%r12)   */
                                        /* ld    %r11,xxx+16@l(%r12) */
 #define BCTR           0x4e800420      /* bctr                      */
 
 
 #define ADDIS_R12_R12  0x3d8c0000      /* addis %r12,%r12,off@ha  */
+#define ADDI_R12_R12   0x398c0000      /* addi %r12,%r12,off@l  */
 #define ADDIS_R2_R2    0x3c420000      /* addis %r2,%r2,off@ha  */
 #define ADDI_R2_R2     0x38420000      /* addi  %r2,%r2,off@l   */
 
+#define LD_R11_0R2     0xe9620000      /* ld    %r11,xxx+0(%r2) */
+#define LD_R2_0R2      0xe8420000      /* ld    %r2,xxx+0(%r2)  */
+
 #define LD_R2_40R1     0xe8410028      /* ld    %r2,40(%r1)     */
 
 /* glink call stub instructions.  We enter with the index in R0.  */
@@ -2111,6 +2117,22 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return ppc64_elf_howto_table[r];
 };
 
+static reloc_howto_type *
+ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                            const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]);
+       i++)
+    if (ppc64_elf_howto_raw[i].name != NULL
+       && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0)
+      return &ppc64_elf_howto_raw[i];
+
+  return NULL;
+}
+
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
@@ -3217,13 +3239,12 @@ struct plt_entry
    ppc_stub_plt_call:
    Used to call a function in a shared library.  If it so happens that
    the plt entry referenced crosses a 64k boundary, then an extra
-   "addis %r12,%r12,1" will be inserted before the load at xxx+8 or
-   xxx+16 as appropriate.
+   "addi %r12,%r12,xxx@toc@l" will be inserted before the "mtctr".
    .   addis   %r12,%r2,xxx@toc@ha
    .   std     %r2,40(%r1)
    .   ld      %r11,xxx+0@toc@l(%r12)
-   .   ld      %r2,xxx+8@toc@l(%r12)
    .   mtctr   %r11
+   .   ld      %r2,xxx+8@toc@l(%r12)
    .   ld      %r11,xxx+16@toc@l(%r12)
    .   bctr
 
@@ -3243,6 +3264,9 @@ struct plt_entry
    .   addi    %r2,%r2,off@l
    .   mtctr   %r11
    .   bctr
+
+   In cases where the "addis" instruction would add zero, the "addis" is
+   omitted and following instructions modified slightly in some cases.
 */
 
 enum ppc_stub_type {
@@ -5782,7 +5806,6 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 {
   struct ppc_link_hash_table *htab;
   asection *s;
-  unsigned int power_of_two;
 
   htab = ppc_hash_table (info);
 
@@ -5834,6 +5857,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (!h->non_got_ref)
     return TRUE;
 
+  /* Don't generate a copy reloc for symbols defined in the executable.  */
+  if (!h->def_dynamic || !h->ref_regular || h->def_regular)
+    return TRUE;
+
   if (ELIMINATE_COPY_RELOCS)
     {
       struct ppc_link_hash_entry * eh;
@@ -5899,29 +5926,9 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
-  /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this.  */
-  power_of_two = bfd_log2 (h->size);
-  if (power_of_two > 4)
-    power_of_two = 4;
-
-  /* Apply the required alignment.  */
   s = htab->dynbss;
-  s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
-    {
-      if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
-       return FALSE;
-    }
-
-  /* Define the symbol as being at this point in the section.  */
-  h->root.u.def.section = s;
-  h->root.u.def.value = s->size;
-
-  /* Increment the section size to make room for the symbol.  */
-  s->size += h->size;
 
-  return TRUE;
+  return _bfd_elf_adjust_dynamic_copy (h, s);
 }
 
 /* If given a function descriptor symbol, hide both the function code
@@ -8192,19 +8199,35 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset)
 #define PPC_HI(v) (((v) >> 16) & 0xffff)
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
-  bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),        p += 4;
-  bfd_put_32 (obfd, STD_R2_40R1, p),                   p += 4;
-  bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4;
-  if (PPC_HA (offset + 8) != PPC_HA (offset))
-    bfd_put_32 (obfd, ADDIS_R12_R12 | 1, p),           p += 4;
-  offset += 8;
-  bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset), p),  p += 4;
-  if (PPC_HA (offset + 8) != PPC_HA (offset))
-    bfd_put_32 (obfd, ADDIS_R12_R12 | 1, p),           p += 4;
-  offset += 8;
-  bfd_put_32 (obfd, MTCTR_R11, p),                     p += 4;
-  bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4;
-  bfd_put_32 (obfd, BCTR, p),                          p += 4;
+  if (PPC_HA (offset) != 0)
+    {
+      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),    p += 4;
+      bfd_put_32 (obfd, STD_R2_40R1, p),                       p += 4;
+      bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p),     p += 4;
+      if (PPC_HA (offset + 16) != PPC_HA (offset))
+       {
+         bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p), p += 4;
+         offset = 0;
+       }
+      bfd_put_32 (obfd, MTCTR_R11, p),                         p += 4;
+      bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p),  p += 4;
+      bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p),        p += 4;
+      bfd_put_32 (obfd, BCTR, p),                              p += 4;
+    }
+  else
+    {
+      bfd_put_32 (obfd, STD_R2_40R1, p),                       p += 4;
+      bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p),      p += 4;
+      if (PPC_HA (offset + 16) != PPC_HA (offset))
+       {
+         bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p),   p += 4;
+         offset = 0;
+       }
+      bfd_put_32 (obfd, MTCTR_R11, p),                         p += 4;
+      bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
+      bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p),   p += 4;
+      bfd_put_32 (obfd, BCTR, p),                              p += 4;
+    }
   return p;
 }
 
@@ -8247,9 +8270,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              + stub_entry->stub_sec->output_offset
              + stub_entry->stub_sec->output_section->vma);
 
-      if (stub_entry->stub_type != ppc_stub_long_branch_r2off)
-       size = 4;
-      else
+      size = 4;
+      if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
          bfd_vma r2off;
 
@@ -8257,12 +8279,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                   - htab->stub_group[stub_entry->id_sec->id].toc_off);
          bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
-         bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
-         loc += 4;
+         size = 12;
+         if (PPC_HA (r2off) != 0)
+           {
+             size = 16;
+             bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+             loc += 4;
+           }
          bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
          loc += 4;
-         off -= 12;
-         size = 16;
+         off -= size - 4;
        }
       bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
 
@@ -8419,10 +8445,18 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       indx = off;
       if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
        {
-         bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
-         loc += 4;
-         bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
-         size = 16;
+         if (PPC_HA (indx) != 0)
+           {
+             size = 16;
+             bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
+             loc += 4;
+             bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
+           }
+         else
+           {
+             size = 12;
+             bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (indx), loc);
+           }
        }
       else
        {
@@ -8432,14 +8466,28 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                   - htab->stub_group[stub_entry->id_sec->id].toc_off);
          bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
-         bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
-         loc += 4;
-         bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
-         loc += 4;
-         bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
-         loc += 4;
+         size = 20;
+         if (PPC_HA (indx) != 0)
+           {
+             size += 4;
+             bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
+             loc += 4;
+             bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
+             loc += 4;
+           }
+         else
+           {
+             bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (indx), loc);
+             loc += 4;
+           }
+
+         if (PPC_HA (r2off) != 0)
+           {
+             size += 4;
+             bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+             loc += 4;
+           }
          bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
-         size = 28;
        }
       loc += 4;
       bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc);
@@ -8578,6 +8626,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
       size = PLT_CALL_STUB_SIZE;
+      if (PPC_HA (off) == 0)
+       size -= 4;
       if (PPC_HA (off + 16) != PPC_HA (off))
        size += 4;
     }
@@ -8585,6 +8635,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
     {
       /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off
         variants.  */
+      bfd_vma r2off = 0;
+
       off = (stub_entry->target_value
             + stub_entry->target_section->output_offset
             + stub_entry->target_section->output_section->vma);
@@ -8600,14 +8652,19 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       size = 4;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
-         off -= 12;
-         size = 16;
+         r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
+                  - htab->stub_group[stub_entry->id_sec->id].toc_off);
+         size = 12;
+         if (PPC_HA (r2off) != 0)
+           size = 16;
+         off -= size - 4;
        }
 
       /* If the branch offset if too big, use a ppc_stub_plt_branch.  */
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
        {
          struct ppc_branch_hash_entry *br_entry;
+         unsigned int indx;
 
          br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
                                             stub_entry->root.string + 9,
@@ -8636,9 +8693,28 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            }
 
          stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch;
-         size = 16;
-         if (stub_entry->stub_type != ppc_stub_plt_branch)
-           size = 28;
+         off = (br_entry->offset
+                + htab->brlt->output_offset
+                + htab->brlt->output_section->vma
+                - elf_gp (htab->brlt->output_section->owner)
+                - htab->stub_group[stub_entry->id_sec->id].toc_off);
+
+         indx = off;
+         if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+           {
+             size = 12;
+             if (PPC_HA (indx) != 0)
+               size = 16;
+           }
+         else
+           {
+             size = 20;
+             if (PPC_HA (indx) != 0)
+               size += 4;
+
+             if (PPC_HA (r2off) != 0)
+               size += 4;
+           }
        }
       else if (info->emitrelocations)
        {
@@ -9896,13 +9972,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    relocation += adjust;
                }
            }
-         if (info->relocatable)
-           continue;
        }
       else
        {
-         if (info->relocatable)
-           continue;
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h_elf, sec, relocation,
@@ -9912,6 +9984,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
       h = (struct ppc_link_hash_entry *) h_elf;
 
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (ppc64_elf_howto_table[r_type], input_bfd,
+                              contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
+
+      if (info->relocatable)
+       continue;
+
       /* TLS optimizations.  Replace instruction sequences and relocs
         based on information we collected in tls_optimize.  We edit
         RELOCS so that --emit-relocs will output something sensible
@@ -10731,7 +10818,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            relocation += htab->stub_group[sec->id].toc_off;
          else
            unresolved_reloc = TRUE;
-         goto dodyn2;
+         goto dodyn;
 
          /* TOC16 relocs.  We want the offset relative to the TOC base,
             which is the address of the start of the TOC plus 0x8000.
@@ -10831,19 +10918,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_UADDR16:
        case R_PPC64_UADDR32:
        case R_PPC64_UADDR64:
-         /* r_symndx will be zero only for relocs against symbols
-            from removed linkonce sections, or sections discarded by
-            a linker script.  */
        dodyn:
-         if (r_symndx == 0)
-           {
-             _bfd_clear_contents (ppc64_elf_howto_table[r_type], input_bfd,
-                                  contents + rel->r_offset);
-             break;
-           }
-         /* Fall thru.  */
-
-       dodyn2:
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
 
This page took 0.03399 seconds and 4 git commands to generate.