Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 868fe5070092a655b164dee378525781bc169286..b96dbc8faadce847a006c87173e314bd8f88adb1 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright (C) 1994-2014 Free Software Foundation, Inc.
+   Copyright (C) 1994-2015 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -147,6 +147,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
 #define ADD_3_12_2     0x7c6c1214
 #define ADD_11_0_11    0x7d605a14
 #define B              0x48000000
+#define BA             0x48000002
 #define BCL_20_31      0x429f0005
 #define BCTR           0x4e800420
 #define BEQLR          0x4d820020
@@ -186,8 +187,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
   HOWTO (R_PPC_NONE,           /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
@@ -2018,19 +2019,28 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
 {
+  unsigned int r_type;
+
   /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
     ppc_elf_howto_init ();
 
-  BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
-  cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)];
+  r_type = ELF32_R_TYPE (dst->r_info);
+  if (r_type >= R_PPC_max)
+    {
+      (*_bfd_error_handler) (_("%B: unrecognised PPC reloc number: %d"),
+                            abfd, r_type);
+      bfd_set_error (bfd_error_bad_value);
+      r_type = R_PPC_NONE;
+    }
+  cache_ptr->howto = ppc_elf_howto_table[r_type];
 
   /* Just because the above assert didn't trigger doesn't mean that
      ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation.  */
   if (!cache_ptr->howto)
     {
       (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
-                             abfd, ELF32_R_TYPE (dst->r_info));
+                             abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
 
       cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
@@ -2056,9 +2066,6 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       return bfd_reloc_ok;
     }
 
-  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
-    return bfd_reloc_outofrange;
-
   if (bfd_is_com_section (symbol->section))
     relocation = 0;
   else
@@ -2628,7 +2635,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
   apuinfo_list_init ();
 
   /* Read in the input sections contents.  */
-  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
+  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
       unsigned long datum;
 
@@ -2918,7 +2925,6 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
     }
 
   count = relplt->size / sizeof (Elf32_External_Rela);
-  stub_vma = glink_vma - (bfd_vma) count * 16;
   /* If the stubs are those for -shared/-pie then we might have
      multiple stubs for each plt entry.  If that is the case then
      there is no way to associate stubs with their plt entries short
@@ -2949,9 +2955,10 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
   if (s == NULL)
     return -1;
 
+  stub_vma = glink_vma;
   names = (char *) (s + count + 1 + (resolv_vma != 0));
-  p = relplt->relocation;
-  for (i = 0; i < count; i++, p++)
+  p = relplt->relocation + count - 1;
+  for (i = 0; i < count; i++)
     {
       size_t len;
 
@@ -2962,6 +2969,9 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
        s->flags |= BSF_GLOBAL;
       s->flags |= BSF_SYNTHETIC;
       s->section = glink;
+      stub_vma -= 16;
+      if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0)
+       stub_vma -= 32;
       s->value = stub_vma - glink->vma;
       s->name = names;
       s->udata.p = NULL;
@@ -2978,7 +2988,7 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s;
-      stub_vma += 16;
+      --p;
     }
 
   /* Add a symbol at the start of the glink branch table.  */
@@ -3249,7 +3259,7 @@ static struct bfd_link_hash_table *
 ppc_elf_link_hash_table_create (bfd *abfd)
 {
   struct ppc_elf_link_hash_table *ret;
-  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 4096 };
+  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12 };
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
@@ -3337,6 +3347,36 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Create a special linker section, used for R_PPC_EMB_SDAI16 and
+   R_PPC_EMB_SDA2I16 pointers.  These sections become part of .sdata
+   and .sdata2.  Create _SDA_BASE_ and _SDA2_BASE too.  */
+
+static bfd_boolean
+ppc_elf_create_linker_section (bfd *abfd,
+                              struct bfd_link_info *info,
+                              flagword flags,
+                              elf_linker_section_t *lsect)
+{
+  asection *s;
+
+  flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+           | SEC_LINKER_CREATED);
+
+  s = bfd_make_section_anyway_with_flags (abfd, lsect->name, flags);
+  if (s == NULL)
+    return FALSE;
+  lsect->section = s;
+
+  /* Define the sym on the first section of this name.  */
+  s = bfd_get_section_by_name (abfd, lsect->name);
+
+  lsect->sym = _bfd_elf_define_linkage_sym (abfd, info, s, lsect->sym_name);
+  if (lsect->sym == NULL)
+    return FALSE;
+  lsect->sym->root.u.def.value = 0x8000;
+  return TRUE;
+}
+
 static bfd_boolean
 ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
 {
@@ -3378,6 +3418,15 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 2))
     return FALSE;
+
+  if (!ppc_elf_create_linker_section (abfd, info, 0,
+                                     &htab->sdata[0]))
+    return FALSE;
+
+  if (!ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
+                                     &htab->sdata[1]))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -3596,59 +3645,15 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       *valp = sym->st_size;
     }
 
-  if ((abfd->flags & DYNAMIC) == 0
-      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
+      && (abfd->flags & DYNAMIC) == 0
+      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
     elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
 \f
-static bfd_boolean
-create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect)
-{
-  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
-
-  lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
-                                    TRUE, FALSE, TRUE);
-  if (lsect->sym == NULL)
-    return FALSE;
-  if (lsect->sym->root.type == bfd_link_hash_new)
-    lsect->sym->non_elf = 0;
-  lsect->sym->ref_regular = 1;
-  _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE);
-  return TRUE;
-}
-
-/* Create a special linker section.  */
-
-static bfd_boolean
-ppc_elf_create_linker_section (bfd *abfd,
-                              struct bfd_link_info *info,
-                              flagword flags,
-                              elf_linker_section_t *lsect)
-{
-  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
-  asection *s;
-
-  flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-           | SEC_LINKER_CREATED);
-
-  /* Record the first bfd that needs the special sections.  */
-  if (!htab->elf.dynobj)
-    htab->elf.dynobj = abfd;
-
-  s = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
-                                         lsect->name,
-                                         flags);
-  if (s == NULL
-      || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
-    return FALSE;
-  lsect->section = s;
-
-  return create_sdata_sym (info, lsect);
-}
-
 /* Find a linker generated pointer with a given addend and type.  */
 
 static elf_linker_section_pointers_t *
@@ -3667,10 +3672,10 @@ elf_find_pointer_linker_section
 /* Allocate a pointer to live in a linker created section.  */
 
 static bfd_boolean
-elf_create_pointer_linker_section (bfd *abfd,
-                                  elf_linker_section_t *lsect,
-                                  struct elf_link_hash_entry *h,
-                                  const Elf_Internal_Rela *rel)
+elf_allocate_pointer_linker_section (bfd *abfd,
+                                    elf_linker_section_t *lsect,
+                                    struct elf_link_hash_entry *h,
+                                    const Elf_Internal_Rela *rel)
 {
   elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
   elf_linker_section_pointers_t *linker_section_ptr;
@@ -3738,6 +3743,8 @@ elf_create_pointer_linker_section (bfd *abfd,
   linker_section_ptr->lsect = lsect;
   *ptr_linker_section_ptr = linker_section_ptr;
 
+  if (!bfd_set_section_alignment (lsect->section->owner, lsect->section, 2))
+    return FALSE;
   linker_section_ptr->offset = lsect->section->size;
   lsect->section->size += 4;
 
@@ -4020,7 +4027,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_HI:
        case R_PPC_GOT_TPREL16_HA:
-         if (!info->executable)
+         if (info->shared)
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -4073,12 +4080,9 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (htab->sdata[0].section == NULL
-             && !ppc_elf_create_linker_section (abfd, info, 0,
-                                                &htab->sdata[0]))
-           return FALSE;
-         if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0],
-                                                 h, rel))
+         htab->sdata[0].sym->ref_regular = 1;
+         if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[0],
+                                                   h, rel))
            return FALSE;
          if (h != NULL)
            {
@@ -4094,12 +4098,9 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (htab->sdata[1].section == NULL
-             && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
-                                                &htab->sdata[1]))
-           return FALSE;
-         if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1],
-                                                 h, rel))
+         htab->sdata[1].sym->ref_regular = 1;
+         if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[1],
+                                                   h, rel))
            return FALSE;
          if (h != NULL)
            {
@@ -4108,21 +4109,16 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          break;
 
+       case R_PPC_SDAREL16:
+         htab->sdata[0].sym->ref_regular = 1;
+         /* Fall thru */
+
        case R_PPC_VLE_SDAREL_LO16A:
        case R_PPC_VLE_SDAREL_LO16D:
        case R_PPC_VLE_SDAREL_HI16A:
        case R_PPC_VLE_SDAREL_HI16D:
        case R_PPC_VLE_SDAREL_HA16A:
        case R_PPC_VLE_SDAREL_HA16D:
-       case R_PPC_SDAREL16:
-         if (htab->sdata[0].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[0]))
-           return FALSE;
-
-         if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[1]))
-           return FALSE;
-
          if (h != NULL)
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
@@ -4147,9 +4143,7 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[1]))
-           return FALSE;
+         htab->sdata[1].sym->ref_regular = 1;
          if (h != NULL)
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
@@ -4166,12 +4160,6 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (htab->sdata[0].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[0]))
-           return FALSE;
-         if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[1]))
-           return FALSE;
          if (h != NULL)
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
@@ -4330,7 +4318,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
-         if (!info->executable)
+         if (info->shared)
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
 
@@ -4850,7 +4838,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
             --secure-plt and we never see REL16 relocs.  */
          if (plt_type == PLT_UNSET)
            plt_type = PLT_OLD;
-         for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+         for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
            if (is_ppc_elf (ibfd))
              {
                if (ppc_elf_tdata (ibfd)->has_rel16)
@@ -5108,6 +5096,9 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
   htab = ppc_elf_hash_table (info);
   htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
                                             FALSE, FALSE, TRUE);
+  if (htab->plt_type != PLT_NEW)
+    htab->params->no_tls_get_addr_opt = TRUE;
+
   if (!htab->params->no_tls_get_addr_opt)
     {
       struct elf_link_hash_entry *opt, *tga;
@@ -5219,7 +5210,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
      notify relocate_section that optimization can be done, and
      adjust got and plt refcounts.  */
   for (pass = 0; pass < 2; ++pass)
-    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
       {
        Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
@@ -5528,9 +5519,24 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             will go to this object, or will remain undefined.  */
          h->plt.plist = NULL;
          h->needs_plt = 0;
+         h->pointer_equality_needed = 0;
        }
       else
        {
+         /* Taking a function's address in a read/write section
+            doesn't require us to define the function symbol in the
+            executable on a plt call stub.  A dynamic reloc can
+            be used instead.  */
+         if (h->pointer_equality_needed
+             && h->type != STT_GNU_IFUNC
+             && !htab->is_vxworks
+             && !ppc_elf_hash_entry (h)->has_sda_refs
+             && !readonly_dynrelocs (h))
+           {
+             h->pointer_equality_needed = 0;
+             h->non_got_ref = 0;
+           }
+
          /* After adjust_dynamic_symbol, non_got_ref set in the
             non-shared case means that we have allocated space in
             .dynbss for the symbol and thus dyn_relocs for this
@@ -5540,12 +5546,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             relocations against this symbol to the PLT entry.  Allow
             dynamic relocs if the reference is weak, and the dynamic
             relocs will not cause text relocation.  */
-         if (!h->ref_regular_nonweak
-             && h->non_got_ref
-             && h->type != STT_GNU_IFUNC
-             && !htab->is_vxworks
-             && !ppc_elf_hash_entry (h)->has_sda_refs
-             && !readonly_dynrelocs (h))
+         else if (!h->ref_regular_nonweak
+                  && h->non_got_ref
+                  && h->type != STT_GNU_IFUNC
+                  && !htab->is_vxworks
+                  && !ppc_elf_hash_entry (h)->has_sda_refs
+                  && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
        }
       return TRUE;
@@ -5582,6 +5588,13 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (!h->non_got_ref)
     return TRUE;
 
+  /* If -z nocopyreloc was given, we won't generate them either.  */
+  if (info->nocopyreloc)
+    {
+      h->non_got_ref = 0;
+      return TRUE;
+    }
+
    /* If we didn't find any dynamic relocs in read-only sections, then
       we'll be keeping the dynamic relocs and avoiding the copy reloc.
       We can't do this if there are any small data relocations.  This
@@ -5598,6 +5611,16 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       return TRUE;
     }
 
+  /* Protected variables do not work with .dynbss.  The copy in
+     .dynbss won't be used by the shared library with the protected
+     definition for the variable.  Text relocations are preferable
+     to an incorrect program.  */
+  if (h->protected_def)
+    {
+      h->non_got_ref = 0;
+      return TRUE;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -5634,7 +5657,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
-  return _bfd_elf_adjust_dynamic_copy (h, s);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
 /* Generate a symbol to mark plt call stubs.  For non-PIC code the sym is
@@ -5685,6 +5708,7 @@ add_stub_sym (struct plt_entry *ent,
       sh->ref_regular_nonweak = 1;
       sh->forced_local = 1;
       sh->non_elf = 0;
+      sh->root.linker_def = 1;
     }
   return TRUE;
 }
@@ -6118,7 +6142,7 @@ static const unsigned char glink_eh_frame_cie[] =
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
-ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ppc_elf_size_dynamic_sections (bfd *output_bfd,
                               struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab;
@@ -6152,7 +6176,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
@@ -6322,14 +6346,19 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (info->shared)
     {
       struct elf_link_hash_entry *sda = htab->sdata[0].sym;
-      if (sda != NULL
-         && !(sda->root.type == bfd_link_hash_defined
-              || sda->root.type == bfd_link_hash_defweak))
-       {
-         sda->root.type = bfd_link_hash_defined;
-         sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
-         sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
-       }
+
+      sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
+      sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
+    }
+  if (info->emitrelocations)
+    {
+      struct elf_link_hash_entry *sda = htab->sdata[0].sym;
+
+      if (sda != NULL && sda->ref_regular)
+       sda->root.u.def.section->flags |= SEC_KEEP;
+      sda = htab->sdata[1].sym;
+      if (sda != NULL && sda->ref_regular)
+       sda->root.u.def.section->flags |= SEC_KEEP;
     }
 
   if (htab->glink != NULL
@@ -6361,6 +6390,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
+             sh->root.linker_def = 1;
            }
          sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
                                     TRUE, FALSE, FALSE);
@@ -6376,6 +6406,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
+             sh->root.linker_def = 1;
            }
        }
     }
@@ -6423,12 +6454,15 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
               || s == htab->sgotplt
               || s == htab->sbss
               || s == htab->dynbss
-              || s == htab->dynsbss
-              || s == htab->sdata[0].section
-              || s == htab->sdata[1].section)
+              || s == htab->dynsbss)
        {
          /* Strip these too.  */
        }
+      else if (s == htab->sdata[0].section
+              || s == htab->sdata[1].section)
+       {
+         strip_section = (s->flags & SEC_KEEP) == 0;
+       }
       else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s),
                             ".rela"))
        {
@@ -6598,6 +6632,46 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+/* Arrange to have _SDA_BASE_ or _SDA2_BASE_ stripped from the output
+   if it looks like nothing is using them.  */
+
+static void
+maybe_strip_sdasym (bfd *output_bfd, elf_linker_section_t *lsect)
+{
+  struct elf_link_hash_entry *sda = lsect->sym;
+
+  if (sda != NULL && !sda->ref_regular && sda->dynindx == -1)
+    {
+      asection *s;
+
+      s = bfd_get_section_by_name (output_bfd, lsect->name);
+      if (s == NULL || bfd_section_removed_from_list (output_bfd, s))
+       {
+         s = bfd_get_section_by_name (output_bfd, lsect->bss_name);
+         if (s == NULL || bfd_section_removed_from_list (output_bfd, s))
+           {
+             sda->def_regular = 0;
+             /* This is somewhat magic.  See elf_link_output_extsym.  */
+             sda->ref_dynamic = 1;
+             sda->forced_local = 0;
+           }
+       }
+    }
+}
+
+void
+ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
+  if (htab != NULL)
+    {
+      maybe_strip_sdasym (info->output_bfd, &htab->sdata[0]);
+      maybe_strip_sdasym (info->output_bfd, &htab->sdata[1]);
+    }
+}
+
+
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
 
 static bfd_boolean
@@ -7124,7 +7198,7 @@ ppc_elf_relax_section (bfd *abfd,
       bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
 
       addr = isec->output_section->vma + isec->output_offset;
-      end_addr = addr + trampoff - 1;
+      end_addr = addr + trampoff;
       addr &= -pagesize;
       crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2;
       if (crossings != 0)
@@ -7132,7 +7206,7 @@ ppc_elf_relax_section (bfd *abfd,
          /* Keep space aligned, to ensure the patch code itself does
             not cross a page.  Don't decrease size calculated on a
             previous pass as otherwise we might never settle on a layout.  */
-         newsize = 15 - (end_addr & 15);
+         newsize = 15 - ((end_addr - 1) & 15);
          newsize += crossings * 16;
          if (relax_info->workaround_size < newsize)
            {
@@ -7336,7 +7410,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
          p += 4;
          bfd_put_32 (output_bfd, BCTR, p);
          p += 4;
-         bfd_put_32 (output_bfd, NOP, p);
+         bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
          p += 4;
        }
       else
@@ -7712,8 +7786,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          + R_PPC_GOT_TPREL16);
              else
                {
-                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
                  rel->r_offset -= d_offset;
+                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
                  r_type = R_PPC_NONE;
                }
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -7746,12 +7820,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  && branch_reloc_hash_match (input_bfd, rel + 1,
                                              htab->tls_get_addr))
                offset = rel[1].r_offset;
+             /* We read the low GOT_TLS insn because we need to keep
+                the destination reg.  It may be something other than
+                the usual r3, and moved to r3 before the call by
+                intervening code.  */
+             insn1 = bfd_get_32 (output_bfd,
+                                 contents + rel->r_offset - d_offset);
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
-                 insn1 = bfd_get_32 (output_bfd,
-                                     contents + rel->r_offset - d_offset);
-                 insn1 &= (1 << 26) - 1;
+                 insn1 &= (0x1f << 21) | (0x1f << 16);
                  insn1 |= 32 << 26;    /* lwz */
                  if (offset != (bfd_vma) -1)
                    {
@@ -7766,7 +7844,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              else
                {
                  /* LE */
-                 insn1 = 0x3c620000;   /* addis 3,2,0 */
+                 insn1 &= 0x1f << 21;
+                 insn1 |= 0x3c020000;  /* addis r,2,0 */
                  if (tls_gd == 0)
                    {
                      /* Was an LD reloc.  */
@@ -8168,7 +8247,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          {
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
-                             outrel.r_addend -= htab->elf.tls_sec->vma;
+                             {
+                               if (htab->elf.tls_sec == NULL)
+                                 outrel.r_addend = 0;
+                               else
+                                 outrel.r_addend -= htab->elf.tls_sec->vma;
+                             }
                          }
                        loc = rsec->contents;
                        loc += (rsec->reloc_count++
@@ -8186,9 +8270,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          value = 1;
                        else if (tls_ty != 0)
                          {
-                           value -= htab->elf.tls_sec->vma + DTP_OFFSET;
-                           if (tls_ty == (TLS_TLS | TLS_TPREL))
-                             value += DTP_OFFSET - TP_OFFSET;
+                           if (htab->elf.tls_sec == NULL)
+                             value = 0;
+                           else
+                             {
+                               value -= htab->elf.tls_sec->vma + DTP_OFFSET;
+                               if (tls_ty == (TLS_TLS | TLS_TPREL))
+                                 value += DTP_OFFSET - TP_OFFSET;
+                             }
 
                            if (tls_ty == (TLS_TLS | TLS_GD))
                              {
@@ -8274,7 +8363,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_DTPREL16_LO:
        case R_PPC_DTPREL16_HI:
        case R_PPC_DTPREL16_HA:
-         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          break;
 
          /* Relocations that may need to be propagated if this is a shared
@@ -8298,18 +8388,21 @@ ppc_elf_relocate_section (bfd *output_bfd,
                bfd_put_32 (output_bfd, insn, p);
              break;
            }
-         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          /* The TPREL16 relocs shouldn't really be used in shared
             libs as they will result in DT_TEXTREL being set, but
             support them anyway.  */
          goto dodyn;
 
        case R_PPC_TPREL32:
-         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          goto dodyn;
 
        case R_PPC_DTPREL32:
-         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          goto dodyn;
 
        case R_PPC_DTPMOD32:
@@ -8695,10 +8788,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
            addend -= SYM_VAL (sda);
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (! ((CONST_STRNEQ (name, ".sdata")
-                   && (name[6] == 0 || name[6] == '.'))
-                  || (CONST_STRNEQ (name, ".sbss")
-                      && (name[5] == 0 || name[5] == '.'))))
+           if (!(strcmp (name, ".sdata") == 0
+                 || strcmp (name, ".sbss") == 0))
              {
                info->callbacks->einfo
                  (_("%P: %B: the target (%s) of a %s relocation is "
@@ -8727,8 +8818,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
            addend -= SYM_VAL (sda);
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (! (CONST_STRNEQ (name, ".sdata2")
-                  || CONST_STRNEQ (name, ".sbss2")))
+           if (!(strcmp (name, ".sdata2") == 0
+                 || strcmp (name, ".sbss2") == 0))
              {
                info->callbacks->einfo
                  (_("%P: %B: the target (%s) of a %s relocation is "
@@ -8795,16 +8886,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (((CONST_STRNEQ (name, ".sdata")
-                 && (name[6] == 0 || name[6] == '.'))
-                || (CONST_STRNEQ (name, ".sbss")
-                    && (name[5] == 0 || name[5] == '.'))))
+           if (strcmp (name, ".sdata") == 0
+               || strcmp (name, ".sbss") == 0)
              {
                reg = 13;
                sda = htab->sdata[0].sym;
              }
-           else if (CONST_STRNEQ (name, ".sdata2")
-                    || CONST_STRNEQ (name, ".sbss2"))
+           else if (strcmp (name, ".sdata2") == 0
+                    || strcmp (name, ".sbss2") == 0)
              {
                reg = 2;
                sda = htab->sdata[1].sym;
@@ -8896,16 +8985,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (((CONST_STRNEQ (name, ".sdata")
-                 && (name[6] == 0 || name[6] == '.'))
-                || (CONST_STRNEQ (name, ".sbss")
-                    && (name[5] == 0 || name[5] == '.'))))
+           if (strcmp (name, ".sdata") == 0
+               || strcmp (name, ".sbss") == 0)
              {
                //reg = 13;
                sda = htab->sdata[0].sym;
              }
-           else if (CONST_STRNEQ (name, ".sdata2")
-                    || CONST_STRNEQ (name, ".sbss2"))
+           else if (strcmp (name, ".sdata2") == 0
+                    || strcmp (name, ".sbss2") == 0)
              {
                //reg = 2;
                sda = htab->sdata[1].sym;
@@ -9140,10 +9227,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
              unsigned int insn;
 
              insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
-             if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
-                 || (insn & (0x3f << 26)) == 24u << 26 /* ori */
-                 || (insn & (0x3f << 26)) == 26u << 26 /* xori */
-                 || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+             if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+               complain = complain_overflow_bitfield;
+             else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+                      || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+                      || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
                complain = complain_overflow_unsigned;
            }
          if (howto->complain_on_overflow != complain)
@@ -9162,30 +9250,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (r == bfd_reloc_overflow)
            {
            overflow:
-             if (warned)
-               continue;
-             if (h != NULL
-                 && h->root.type == bfd_link_hash_undefweak
-                 && howto->pc_relative)
+             /* On code like "if (foo) foo();" don't report overflow
+                on a branch to zero when foo is undefined.  */
+             if (!warned
+                 && !(h != NULL
+                      && (h->root.type == bfd_link_hash_undefweak
+                          || h->root.type == bfd_link_hash_undefined)
+                      && is_branch_reloc (r_type)))
                {
-                 /* Assume this is a call protected by other code that
-                    detect the symbol is undefined.  If this is the case,
-                    we can safely ignore the overflow.  If not, the
-                    program is hosed anyway, and a little warning isn't
-                    going to help.  */
-
-                 continue;
+                 if (!((*info->callbacks->reloc_overflow)
+                       (info, (h ? &h->root : NULL), sym_name,
+                        howto->name, rel->r_addend,
+                        input_bfd, input_section, rel->r_offset)))
+                   return FALSE;
                }
-
-             if (! (*info->callbacks->reloc_overflow) (info,
-                                                       (h ? &h->root : NULL),
-                                                       sym_name,
-                                                       howto->name,
-                                                       rel->r_addend,
-                                                       input_bfd,
-                                                       input_section,
-                                                       rel->r_offset))
-               return FALSE;
            }
          else
            {
@@ -9224,8 +9302,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
       relax_info = elf_section_data (input_section)->sec_info;
       if (relax_info->workaround_size != 0)
-       memset (contents + input_section->size - relax_info->workaround_size,
-               0, relax_info->workaround_size);
+       {
+         bfd_byte *p;
+         unsigned int n;
+         bfd_byte fill[4];
+
+         bfd_put_32 (input_bfd, BA, fill);
+         p = contents + input_section->size - relax_info->workaround_size;
+         n = relax_info->workaround_size >> 2;
+         while (n--)
+           {
+             memcpy (p, fill, 4);
+             p += 4;
+           }
+       }
 
       /* The idea is: Replace the last instruction on a page with a
         branch to a patch area.  Put the insn there followed by a
@@ -9279,27 +9369,56 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (is_data)
            continue;
 
-         /* Some instructions can be left alone too.  In this
-            category are most insns that unconditionally change
-            control flow, and isync.  Of these, some *must* be left
-            alone, for example, the "bcl 20, 31, label" used in pic
-            sequences to give the address of the next insn.  twui
-            and twu apparently are not safe.  */
+         /* Some instructions can be left alone too.  Unconditional
+            branches, except for bcctr with BO=0x14 (bctr, bctrl),
+            avoid the icache failure.
+
+            The problem occurs due to prefetch across a page boundary
+            where stale instructions can be fetched from the next
+            page, and the mechanism for flushing these bad
+            instructions fails under certain circumstances.  The
+            unconditional branches:
+            1) Branch: b, bl, ba, bla,
+            2) Branch Conditional: bc, bca, bcl, bcla,
+            3) Branch Conditional to Link Register: bclr, bclrl,
+            where (2) and (3) have BO=0x14 making them unconditional,
+            prevent the bad prefetch because the prefetch itself is
+            affected by these instructions.  This happens even if the
+            instruction is not executed.
+
+            A bctr example:
+            .
+            .  lis 9,new_page@ha
+            .  addi 9,9,new_page@l
+            .  mtctr 9
+            .  bctr
+            .  nop
+            .  nop
+            . new_page:
+            .
+            The bctr is not predicted taken due to ctr not being
+            ready, so prefetch continues on past the bctr into the
+            new page which might have stale instructions.  If they
+            fail to be flushed, then they will be executed after the
+            bctr executes.  Either of the following modifications
+            prevent the bad prefetch from happening in the first
+            place:
+            .
+            .  lis 9,new_page@ha        lis 9,new_page@ha      
+            .  addi 9,9,new_page@l      addi 9,9,new_page@l    
+            .  mtctr 9                  mtctr 9                        
+            .  bctr                     bctr                   
+            .  nop                      b somewhere_else
+            .  b somewhere_else         nop                    
+            . new_page:                new_page:               
+            .  */
          insn = bfd_get_32 (input_bfd, contents + offset);
-         if (insn == 0
-             || (insn & (0x3f << 26)) == (18u << 26)        /* b */
-             || ((insn & (0x3f << 26)) == (16u << 26)       /* bc always */
-                 && (insn & (0x14 << 21)) == (0x14 << 21))
-             || ((insn & (0x3f << 26)) == (19u << 26)       /* blr, bctr */
-                 && (insn & (0x14 << 21)) == (0x14 << 21)
-                 && (insn & (0x1ff << 1)) == (16u << 1))
-             || (insn & (0x3f << 26)) == (17u << 26)        /* sc */
+         if ((insn & (0x3f << 26)) == (18u << 26)          /* b,bl,ba,bla */
+             || ((insn & (0x3f << 26)) == (16u << 26)      /* bc,bcl,bca,bcla*/
+                 && (insn & (0x14 << 21)) == (0x14 << 21)) /*   with BO=0x14 */
              || ((insn & (0x3f << 26)) == (19u << 26)
-                 && ((insn & (0x3ff << 1)) == (38u << 1)    /* rfmci */
-                     || (insn & (0x3ff << 1)) == (50u << 1) /* rfi */
-                     || (insn & (0x3ff << 1)) == (51u << 1) /* rfci */
-                     || (insn & (0x3ff << 1)) == (82u << 1) /* rfsvc */
-                     || (insn & (0x3ff << 1)) == (150u << 1))) /* isync */)
+                 && (insn & (0x3ff << 1)) == (16u << 1)    /* bclr,bclrl */
+                 && (insn & (0x14 << 21)) == (0x14 << 21)))/*   with BO=0x14 */
            continue;
 
          patch_addr = (start_addr + input_section->size
@@ -10086,7 +10205,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       p += htab->glink_pltresolve;
       endp = htab->glink->contents;
       endp += htab->glink->size - GLINK_PLTRESOLVE;
-      while (p < endp - 8 * 4)
+      while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4))
        {
          bfd_put_32 (output_bfd, B + endp - p, p);
          p += 4;
@@ -10101,6 +10220,39 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
              + htab->glink->output_section->vma
              + htab->glink->output_offset);
 
+      if (htab->params->ppc476_workaround)
+       {
+         /* Ensure that a call stub at the end of a page doesn't
+            result in prefetch over the end of the page into the
+            glink branch table.  */
+         bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+         bfd_vma page_addr;
+         bfd_vma glink_start = (htab->glink->output_section->vma
+                                + htab->glink->output_offset);
+
+         for (page_addr = res0 & -pagesize;
+              page_addr > glink_start;
+              page_addr -= pagesize)
+           {
+             /* We have a plt call stub that may need fixing.  */
+             bfd_byte *loc;
+             unsigned int insn;
+
+             loc = htab->glink->contents + page_addr - 4 - glink_start;
+             insn = bfd_get_32 (output_bfd, loc);
+             if (insn == BCTR)
+               {
+                 /* By alignment, we know that there must be at least
+                    one other call stub before this one.  */
+                 insn = bfd_get_32 (output_bfd, loc - 16);
+                 if (insn == BCTR)
+                   bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc);
+                 else
+                   bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc);
+               }
+           }
+       }
+
       /* Last comes the PLTresolve stub.  */
       if (info->shared)
        {
@@ -10108,7 +10260,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
          for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
            {
-             bfd_put_32 (output_bfd, pic_plt_resolve[i], p);
+             unsigned int insn = pic_plt_resolve[i];
+
+             if (htab->params->ppc476_workaround && insn == NOP)
+               insn = BA + 0;
+             bfd_put_32 (output_bfd, insn, p);
              p += 4;
            }
          p -= 4 * ARRAY_SIZE (pic_plt_resolve);
@@ -10142,7 +10298,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        {
          for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
            {
-             bfd_put_32 (output_bfd, plt_resolve[i], p);
+             unsigned int insn = plt_resolve[i];
+
+             if (htab->params->ppc476_workaround && insn == NOP)
+               insn = BA + 0;
+             bfd_put_32 (output_bfd, insn, p);
              p += 4;
            }
          p -= 4 * ARRAY_SIZE (plt_resolve);
@@ -10199,20 +10359,21 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   return ret;
 }
 \f
-#define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
+#define TARGET_LITTLE_SYM      powerpc_elf32_le_vec
 #define TARGET_LITTLE_NAME     "elf32-powerpcle"
-#define TARGET_BIG_SYM         bfd_elf32_powerpc_vec
+#define TARGET_BIG_SYM         powerpc_elf32_vec
 #define TARGET_BIG_NAME                "elf32-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
 #define ELF_TARGET_ID          PPC32_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC
 #ifdef __QNXTARGET__
 #define ELF_MAXPAGESIZE                0x1000
+#define ELF_COMMONPAGESIZE     0x1000
 #else
 #define ELF_MAXPAGESIZE                0x10000
+#define ELF_COMMONPAGESIZE     0x10000
 #endif
 #define ELF_MINPAGESIZE                0x1000
-#define ELF_COMMONPAGESIZE     0x1000
 #define elf_info_to_howto      ppc_elf_info_to_howto
 
 #ifdef  EM_CYGNUS_POWERPC
@@ -10277,7 +10438,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #undef  TARGET_LITTLE_NAME
 
 #undef  TARGET_BIG_SYM
-#define TARGET_BIG_SYM  bfd_elf32_powerpc_freebsd_vec
+#define TARGET_BIG_SYM  powerpc_elf32_fbsd_vec
 #undef  TARGET_BIG_NAME
 #define TARGET_BIG_NAME "elf32-powerpc-freebsd"
 
@@ -10295,7 +10456,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #undef TARGET_LITTLE_NAME
 
 #undef TARGET_BIG_SYM
-#define TARGET_BIG_SYM         bfd_elf32_powerpc_vxworks_vec
+#define TARGET_BIG_SYM         powerpc_elf32_vxworks_vec
 #undef TARGET_BIG_NAME
 #define TARGET_BIG_NAME                "elf32-powerpc-vxworks"
 
This page took 0.040415 seconds and 4 git commands to generate.