Add output_type to bfd_link_info
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 8429e8f95b7ff23764b3118482f2c218d654205a..8415f1ece2b8a6f72299e7e219372c8ca2b0caae 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
 /* 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.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -187,8 +187,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
   HOWTO (R_PPC_NONE,           /* type */
         0,                     /* rightshift */
   /* 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 */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
@@ -2019,19 +2019,28 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
 {
                       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 ();
 
   /* 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"),
 
   /* 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];
       bfd_set_error (bfd_error_bad_value);
 
       cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
@@ -2057,9 +2066,6 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       return bfd_reloc_ok;
     }
 
       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
   if (bfd_is_com_section (symbol->section))
     relocation = 0;
   else
@@ -2919,7 +2925,6 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
     }
 
   count = relplt->size / sizeof (Elf32_External_Rela);
     }
 
   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
   /* 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
@@ -2950,9 +2955,10 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
   if (s == NULL)
     return -1;
 
   if (s == NULL)
     return -1;
 
+  stub_vma = glink_vma;
   names = (char *) (s + count + 1 + (resolv_vma != 0));
   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;
 
     {
       size_t len;
 
@@ -2963,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;
        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;
       s->value = stub_vma - glink->vma;
       s->name = names;
       s->udata.p = NULL;
@@ -2979,7 +2988,7 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s;
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s;
-      stub_vma += 16;
+      --p;
     }
 
   /* Add a symbol at the start of the glink branch table.  */
     }
 
   /* Add a symbol at the start of the glink branch table.  */
@@ -3071,7 +3080,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC_TPREL16_LO:
     case R_PPC_TPREL16_HI:
     case R_PPC_TPREL16_HA:
     case R_PPC_TPREL16_LO:
     case R_PPC_TPREL16_HI:
     case R_PPC_TPREL16_HA:
-      return !info->executable;
+      return !bfd_link_executable (info);
     }
 }
 
     }
 }
 
@@ -3126,7 +3135,11 @@ struct ppc_elf_link_hash_entry
 
   /* Nonzero if we have seen a small data relocation referring to this
      symbol.  */
 
   /* Nonzero if we have seen a small data relocation referring to this
      symbol.  */
-  unsigned char has_sda_refs;
+  unsigned char has_sda_refs : 1;
+
+  /* Flag use of given relocations.  */
+  unsigned char has_addr16_ha : 1;
+  unsigned char has_addr16_lo : 1;
 };
 
 #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
 };
 
 #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
@@ -3250,7 +3263,7 @@ static struct bfd_link_hash_table *
 ppc_elf_link_hash_table_create (bfd *abfd)
 {
   struct ppc_elf_link_hash_table *ret;
 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, 12 };
+  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12, 0 };
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
@@ -3452,7 +3465,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL)
     return FALSE;
 
   if (s == NULL)
     return FALSE;
 
-  if (! info->shared)
+  if (! bfd_link_pic (info))
     {
       htab->relbss = bfd_get_linker_section (abfd, ".rela.bss");
       flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
     {
       htab->relbss = bfd_get_linker_section (abfd, ".rela.bss");
       flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
@@ -3609,7 +3622,7 @@ ppc_elf_add_symbol_hook (bfd *abfd,
                         bfd_vma *valp)
 {
   if (sym->st_shndx == SHN_COMMON
                         bfd_vma *valp)
 {
   if (sym->st_shndx == SHN_COMMON
-      && !info->relocatable
+      && !bfd_link_relocatable (info)
       && is_ppc_elf (info->output_bfd)
       && sym->st_size <= elf_gp_size (abfd))
     {
       && is_ppc_elf (info->output_bfd)
       && sym->st_size <= elf_gp_size (abfd))
     {
@@ -3640,7 +3653,7 @@ ppc_elf_add_symbol_hook (bfd *abfd,
        || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
       && (abfd->flags & DYNAMIC) == 0
       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
        || 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;
+    elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -3863,7 +3876,7 @@ ppc_elf_check_relocs (bfd *abfd,
   asection *got2, *sreloc;
   struct elf_link_hash_entry *tga;
 
   asection *got2, *sreloc;
   struct elf_link_hash_entry *tga;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   /* Don't do anything special with non-loaded, non-alloced sections.
     return TRUE;
 
   /* Don't do anything special with non-loaded, non-alloced sections.
@@ -3960,14 +3973,14 @@ ppc_elf_check_relocs (bfd *abfd,
              /* STT_GNU_IFUNC symbols must have a PLT entry;
                 In a non-pie executable even when there are
                 no plt calls.  */
              /* STT_GNU_IFUNC symbols must have a PLT entry;
                 In a non-pie executable even when there are
                 no plt calls.  */
-             if (!info->shared
+             if (!bfd_link_pic (info)
                  || is_branch_reloc (r_type))
                {
                  bfd_vma addend = 0;
                  if (r_type == R_PPC_PLTREL24)
                    {
                      ppc_elf_tdata (abfd)->makes_plt_call = 1;
                  || is_branch_reloc (r_type))
                {
                  bfd_vma addend = 0;
                  if (r_type == R_PPC_PLTREL24)
                    {
                      ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                     if (info->shared)
+                     if (bfd_link_pic (info))
                        addend = rel->r_addend;
                    }
                  if (!update_plt_info (abfd, ifunc, got2, addend))
                        addend = rel->r_addend;
                    }
                  if (!update_plt_info (abfd, ifunc, got2, addend))
@@ -4018,7 +4031,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:
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_HI:
        case R_PPC_GOT_TPREL16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -4057,7 +4070,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* We may also need a plt entry if the symbol turns out to be
             an ifunc.  */
 
          /* We may also need a plt entry if the symbol turns out to be
             an ifunc.  */
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
            {
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
@@ -4066,7 +4079,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
 
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4084,7 +4097,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4129,7 +4142,7 @@ ppc_elf_check_relocs (bfd *abfd,
          break;
 
        case R_PPC_EMB_SDA2REL:
          break;
 
        case R_PPC_EMB_SDA2REL:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4146,7 +4159,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_VLE_SDA21:
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_RELSDA:
        case R_PPC_VLE_SDA21:
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_RELSDA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4163,7 +4176,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_EMB_NADDR16_LO:
        case R_PPC_EMB_NADDR16_HI:
        case R_PPC_EMB_NADDR16_HA:
        case R_PPC_EMB_NADDR16_LO:
        case R_PPC_EMB_NADDR16_HI:
        case R_PPC_EMB_NADDR16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4207,7 +4220,7 @@ ppc_elf_check_relocs (bfd *abfd,
              if (r_type == R_PPC_PLTREL24)
                {
                  ppc_elf_tdata (abfd)->makes_plt_call = 1;
              if (r_type == R_PPC_PLTREL24)
                {
                  ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    addend = rel->r_addend;
                }
              h->needs_plt = 1;
                    addend = rel->r_addend;
                }
              h->needs_plt = 1;
@@ -4273,7 +4286,7 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          if (h != NULL && h->type == STT_GNU_IFUNC)
            {
            }
          if (h != NULL && h->type == STT_GNU_IFUNC)
            {
-             if (info->shared)
+             if (bfd_link_pic (info))
                {
                  info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
                                          abfd, sec, rel->r_offset,
                {
                  info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
                                          abfd, sec, rel->r_offset,
@@ -4309,7 +4322,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
 
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
 
@@ -4322,7 +4335,7 @@ ppc_elf_check_relocs (bfd *abfd,
          if (h == NULL
              && got2 != NULL
              && (sec->flags & SEC_CODE) != 0
          if (h == NULL
              && got2 != NULL
              && (sec->flags & SEC_CODE) != 0
-             && info->shared
+             && bfd_link_pic (info)
              && htab->plt_type == PLT_UNSET)
            {
              /* Old -fPIC gcc code has .long LCTOC1-LCFx just before
              && htab->plt_type == PLT_UNSET)
            {
              /* Old -fPIC gcc code has .long LCTOC1-LCFx just before
@@ -4357,7 +4370,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_ADDR16_HA:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
        case R_PPC_ADDR16_HA:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
            {
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
@@ -4367,6 +4380,10 @@ ppc_elf_check_relocs (bfd *abfd,
              /* We may need a copy reloc too.  */
              h->non_got_ref = 1;
              h->pointer_equality_needed = 1;
              /* We may need a copy reloc too.  */
              h->non_got_ref = 1;
              h->pointer_equality_needed = 1;
+             if (r_type == R_PPC_ADDR16_HA)
+               ppc_elf_hash_entry (h)->has_addr16_ha = 1;
+             if (r_type == R_PPC_ADDR16_LO)
+               ppc_elf_hash_entry (h)->has_addr16_lo = 1;
            }
          goto dodyn;
 
            }
          goto dodyn;
 
@@ -4391,7 +4408,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_ADDR14:
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_ADDR14:
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
            {
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
@@ -4423,14 +4440,14 @@ ppc_elf_check_relocs (bfd *abfd,
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && (must_be_dyn_reloc (info, r_type)
                   || (h != NULL
                       && (!SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
               && (must_be_dyn_reloc (info, r_type)
                   || (h != NULL
                       && (!SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
@@ -4801,7 +4818,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       if (htab->params->plt_style == PLT_OLD)
        htab->plt_type = PLT_OLD;
 
       if (htab->params->plt_style == PLT_OLD)
        htab->plt_type = PLT_OLD;
-      else if (info->shared
+      else if (bfd_link_pic (info)
               && htab->elf.dynamic_sections_created
               && (h = elf_link_hash_lookup (&htab->elf, "_mcount",
                                             FALSE, FALSE, TRUE)) != NULL
               && htab->elf.dynamic_sections_created
               && (h = elf_link_hash_lookup (&htab->elf, "_mcount",
                                             FALSE, FALSE, TRUE)) != NULL
@@ -4917,7 +4934,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
   const Elf_Internal_Rela *rel, *relend;
   asection *got2;
 
   const Elf_Internal_Rela *rel, *relend;
   asection *got2;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   if ((sec->flags & SEC_ALLOC) == 0)
     return TRUE;
 
   if ((sec->flags & SEC_ALLOC) == 0)
@@ -4963,7 +4980,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
       if (!htab->is_vxworks
          && h == NULL
          && local_got_refcounts != NULL
       if (!htab->is_vxworks
          && h == NULL
          && local_got_refcounts != NULL
-         && (!info->shared
+         && (!bfd_link_pic (info)
              || is_branch_reloc (r_type)))
        {
          struct plt_entry **local_plt = (struct plt_entry **)
              || is_branch_reloc (r_type)))
        {
          struct plt_entry **local_plt = (struct plt_entry **)
@@ -4976,7 +4993,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
-             if (r_type == R_PPC_PLTREL24 && info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
              if (ent->plt.refcount > 0)
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
              if (ent->plt.refcount > 0)
@@ -5011,7 +5028,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
            {
              if (h->got.refcount > 0)
                h->got.refcount--;
            {
              if (h->got.refcount > 0)
                h->got.refcount--;
-             if (!info->shared)
+             if (!bfd_link_pic (info))
                {
                  struct plt_entry *ent;
 
                {
                  struct plt_entry *ent;
 
@@ -5047,7 +5064,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
-         if (info->shared)
+         if (bfd_link_pic (info))
            break;
 
        case R_PPC_PLT32:
            break;
 
        case R_PPC_PLT32:
@@ -5061,7 +5078,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
-             if (r_type == R_PPC_PLTREL24 && info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
                addend = rel->r_addend;
              ent = find_plt_ent (&h->plt.plist, got2, addend);
              if (ent != NULL && ent->plt.refcount > 0)
                addend = rel->r_addend;
              ent = find_plt_ent (&h->plt.plist, got2, addend);
              if (ent != NULL && ent->plt.refcount > 0)
@@ -5087,6 +5104,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);
   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;
   if (!htab->params->no_tls_get_addr_opt)
     {
       struct elf_link_hash_entry *opt, *tga;
@@ -5184,7 +5204,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
   struct ppc_elf_link_hash_table *htab;
   int pass;
 
   struct ppc_elf_link_hash_table *htab;
   int pass;
 
-  if (info->relocatable || !info->executable)
+  if (bfd_link_relocatable (info) || !bfd_link_executable (info))
     return TRUE;
 
   htab = ppc_elf_hash_table (info);
     return TRUE;
 
   htab = ppc_elf_hash_table (info);
@@ -5357,7 +5377,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      struct plt_entry *ent;
                      bfd_vma addend = 0;
 
                      struct plt_entry *ent;
                      bfd_vma addend = 0;
 
-                     if (info->shared
+                     if (bfd_link_pic (info)
                          && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
                        addend = rel[1].r_addend;
                      ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
                          && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
                        addend = rel[1].r_addend;
                      ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
@@ -5542,6 +5562,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                   && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
        }
                   && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
        }
+      h->protected_def = 0;
       return TRUE;
     }
   else
       return TRUE;
     }
   else
@@ -5568,13 +5589,42 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
-  if (info->shared)
-    return TRUE;
+  if (bfd_link_pic (info))
+    {
+      h->protected_def = 0;
+      return TRUE;
+    }
 
   /* If there are no references to this symbol that do not use the
      GOT, we don't need to generate a copy reloc.  */
   if (!h->non_got_ref)
 
   /* If there are no references to this symbol that do not use the
      GOT, we don't need to generate a copy reloc.  */
   if (!h->non_got_ref)
-    return TRUE;
+    {
+      h->protected_def = 0;
+      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.  Editing to PIC, or text relocations
+     are preferable to an incorrect program.  */
+  if (h->protected_def)
+    {
+      if (ELIMINATE_COPY_RELOCS
+         && ppc_elf_hash_entry (h)->has_addr16_ha
+         && ppc_elf_hash_entry (h)->has_addr16_lo
+         && htab->params->pic_fixup == 0
+         && info->disable_target_specific_optimizations <= 1)
+       htab->params->pic_fixup = 1;
+      h->non_got_ref = 0;
+      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.
 
    /* 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.
@@ -5648,7 +5698,7 @@ add_stub_sym (struct plt_entry *ent,
   const char *stub;
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
   const char *stub;
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     stub = ".plt_pic32.";
   else
     stub = ".plt_call32.";
     stub = ".plt_pic32.";
   else
     stub = ".plt_call32.";
@@ -5679,6 +5729,7 @@ add_stub_sym (struct plt_entry *ent,
       sh->ref_regular_nonweak = 1;
       sh->forced_local = 1;
       sh->non_elf = 0;
       sh->ref_regular_nonweak = 1;
       sh->forced_local = 1;
       sh->non_elf = 0;
+      sh->root.linker_def = 1;
     }
   return TRUE;
 }
     }
   return TRUE;
 }
@@ -5756,7 +5807,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              }
 
            dyn = htab->elf.dynamic_sections_created;
              }
 
            dyn = htab->elf.dynamic_sections_created;
-           if (info->shared
+           if (bfd_link_pic (info)
                || h->type == STT_GNU_IFUNC
                || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
              {
                || h->type == STT_GNU_IFUNC
                || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
              {
@@ -5774,7 +5825,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                    ent->plt.offset = plt_offset;
 
                    s = htab->glink;
                    ent->plt.offset = plt_offset;
 
                    s = htab->glink;
-                   if (!doneone || info->shared)
+                   if (!doneone || bfd_link_pic (info))
                      {
                        glink_offset = s->size;
                        s->size += GLINK_ENTRY_SIZE;
                      {
                        glink_offset = s->size;
                        s->size += GLINK_ENTRY_SIZE;
@@ -5783,7 +5834,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                          s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
                      }
                    if (!doneone
                          s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
                      }
                    if (!doneone
-                       && !info->shared
+                       && !bfd_link_pic (info)
                        && h->def_dynamic
                        && !h->def_regular)
                      {
                        && h->def_dynamic
                        && !h->def_regular)
                      {
@@ -5822,7 +5873,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                           relocations, and is required to make
                           function pointers compare as equal between
                           the normal executable and the shared library.  */
                           relocations, and is required to make
                           function pointers compare as equal between
                           the normal executable and the shared library.  */
-                       if (! info->shared
+                       if (! bfd_link_pic (info)
                            && h->def_dynamic
                            && !h->def_regular)
                          {
                            && h->def_dynamic
                            && !h->def_regular)
                          {
@@ -5856,7 +5907,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                        if (htab->plt_type == PLT_VXWORKS)
                          {
                            /* Allocate space for the unloaded relocations.  */
                        if (htab->plt_type == PLT_VXWORKS)
                          {
                            /* Allocate space for the unloaded relocations.  */
-                           if (!info->shared
+                           if (!bfd_link_pic (info)
                                && htab->elf.dynamic_sections_created)
                              {
                                if (ent->plt.offset
                                && htab->elf.dynamic_sections_created)
                              {
                                if (ent->plt.offset
@@ -5899,7 +5950,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     }
 
   eh = (struct ppc_elf_link_hash_entry *) h;
     }
 
   eh = (struct ppc_elf_link_hash_entry *) h;
-  if (eh->elf.got.refcount > 0)
+  if (eh->elf.got.refcount > 0
+      || (ELIMINATE_COPY_RELOCS
+         && !eh->elf.def_regular
+         && eh->elf.protected_def
+         && eh->has_addr16_ha
+         && eh->has_addr16_lo
+         && htab->params->pic_fixup > 0))
     {
       bfd_boolean dyn;
       unsigned int need;
     {
       bfd_boolean dyn;
       unsigned int need;
@@ -5942,7 +5999,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        {
          eh->elf.got.offset = allocate_got (htab, need);
          dyn = htab->elf.dynamic_sections_created;
        {
          eh->elf.got.offset = allocate_got (htab, need);
          dyn = htab->elf.dynamic_sections_created;
-         if ((info->shared
+         if ((bfd_link_pic (info)
               || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
              && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
                  || eh->elf.root.type != bfd_link_hash_undefweak))
               || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
              && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
                  || eh->elf.root.type != bfd_link_hash_undefweak))
@@ -5973,7 +6030,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
      space for relocs that have become local due to symbol visibility
      changes.  */
 
      space for relocs that have become local due to symbol visibility
      changes.  */
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       /* Relocs that use pc_count are those that appear on a call insn,
         or certain REL relocs (see must_be_dyn_reloc) that can be
     {
       /* Relocs that use pc_count are those that appear on a call insn,
         or certain REL relocs (see must_be_dyn_reloc) that can be
@@ -6042,7 +6099,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         dynamic.  */
 
       if (!h->non_got_ref
         dynamic.  */
 
       if (!h->non_got_ref
-         && !h->def_regular)
+         && !h->def_regular
+         && !(h->protected_def
+              && eh->has_addr16_ha
+              && eh->has_addr16_lo
+              && htab->params->pic_fixup > 0))
        {
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
        {
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
@@ -6130,7 +6191,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
          BFD_ASSERT (s != NULL);
        {
          s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
          BFD_ASSERT (s != NULL);
@@ -6230,7 +6291,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
            else
              {
                *local_got = allocate_got (htab, need);
            else
              {
                *local_got = allocate_got (htab, need);
-               if (info->shared)
+               if (bfd_link_pic (info))
                  {
                    asection *srel = htab->relgot;
                    if ((*lgot_masks & PLT_IFUNC) != 0)
                  {
                    asection *srel = htab->relgot;
                    if ((*lgot_masks & PLT_IFUNC) != 0)
@@ -6265,7 +6326,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                ent->plt.offset = plt_offset;
 
                s = htab->glink;
                ent->plt.offset = plt_offset;
 
                s = htab->glink;
-               if (!doneone || info->shared)
+               if (!doneone || bfd_link_pic (info))
                  {
                    glink_offset = s->size;
                    s->size += GLINK_ENTRY_SIZE;
                  {
                    glink_offset = s->size;
                    s->size += GLINK_ENTRY_SIZE;
@@ -6289,7 +6350,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
   if (htab->tlsld_got.refcount > 0)
     {
       htab->tlsld_got.offset = allocate_got (htab, 8);
   if (htab->tlsld_got.refcount > 0)
     {
       htab->tlsld_got.offset = allocate_got (htab, 8);
-      if (info->shared)
+      if (bfd_link_pic (info))
        htab->relgot->size += sizeof (Elf32_External_Rela);
     }
   else
        htab->relgot->size += sizeof (Elf32_External_Rela);
     }
   else
@@ -6313,7 +6374,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 
       htab->elf.hgot->root.u.def.value = g_o_t;
     }
 
       htab->elf.hgot->root.u.def.value = g_o_t;
     }
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       struct elf_link_hash_entry *sda = htab->sdata[0].sym;
 
     {
       struct elf_link_hash_entry *sda = htab->sdata[0].sym;
 
@@ -6360,6 +6421,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
              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);
            }
          sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
                                     TRUE, FALSE, FALSE);
@@ -6375,6 +6437,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
+             sh->root.linker_def = 1;
            }
        }
     }
            }
        }
     }
@@ -6387,7 +6450,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
     {
       s = htab->glink_eh_frame;
       s->size = sizeof (glink_eh_frame_cie) + 20;
     {
       s = htab->glink_eh_frame;
       s->size = sizeof (glink_eh_frame_cie) + 20;
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          s->size += 4;
          if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256)
        {
          s->size += 4;
          if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256)
@@ -6484,7 +6547,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -6563,7 +6626,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       /* Augmentation.  */
       p += 1;
 
       /* Augmentation.  */
       p += 1;
 
-      if (info->shared
+      if (bfd_link_pic (info)
          && htab->elf.dynamic_sections_created)
        {
          bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2;
          && htab->elf.dynamic_sections_created)
        {
          bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2;
@@ -6681,6 +6744,7 @@ static const int stub_entry[] =
 struct ppc_elf_relax_info
 {
   unsigned int workaround_size;
 struct ppc_elf_relax_info
 {
   unsigned int workaround_size;
+  unsigned int picfixup_size;
 };
 
 /* This function implements long branch trampolines, and the ppc476
 };
 
 /* This function implements long branch trampolines, and the ppc476
@@ -6694,9 +6758,9 @@ ppc_elf_relax_section (bfd *abfd,
                       struct bfd_link_info *link_info,
                       bfd_boolean *again)
 {
                       struct bfd_link_info *link_info,
                       bfd_boolean *again)
 {
-  struct one_fixup
+  struct one_branch_fixup
   {
   {
-    struct one_fixup *next;
+    struct one_branch_fixup *next;
     asection *tsec;
     /* Final link, can use the symbol offset.  For a
        relocatable link we use the symbol's index.  */
     asection *tsec;
     /* Final link, can use the symbol offset.  For a
        relocatable link we use the symbol's index.  */
@@ -6709,12 +6773,12 @@ ppc_elf_relax_section (bfd *abfd,
   Elf_Internal_Sym *isymbuf = NULL;
   Elf_Internal_Rela *internal_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend = NULL;
   Elf_Internal_Sym *isymbuf = NULL;
   Elf_Internal_Rela *internal_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend = NULL;
-  struct one_fixup *fixups = NULL;
+  struct one_branch_fixup *branch_fixups = NULL;
   struct ppc_elf_relax_info *relax_info = NULL;
   unsigned changes = 0;
   bfd_boolean workaround_change;
   struct ppc_elf_link_hash_table *htab;
   struct ppc_elf_relax_info *relax_info = NULL;
   unsigned changes = 0;
   bfd_boolean workaround_change;
   struct ppc_elf_link_hash_table *htab;
-  bfd_size_type trampbase, trampoff, newsize;
+  bfd_size_type trampbase, trampoff, newsize, picfixup_size;
   asection *got2;
   bfd_boolean maybe_pasted;
 
   asection *got2;
   bfd_boolean maybe_pasted;
 
@@ -6730,7 +6794,7 @@ ppc_elf_relax_section (bfd *abfd,
   /* We cannot represent the required PIC relocs in the output, so don't
      do anything.  The linker doesn't support mixing -shared and -r
      anyway.  */
   /* We cannot represent the required PIC relocs in the output, so don't
      do anything.  The linker doesn't support mixing -shared and -r
      anyway.  */
-  if (link_info->relocatable && link_info->shared)
+  if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info))
     return TRUE;
 
   htab = ppc_elf_hash_table (link_info);
     return TRUE;
 
   htab = ppc_elf_hash_table (link_info);
@@ -6746,7 +6810,8 @@ ppc_elf_relax_section (bfd *abfd,
              || isec->sec_info_type == SEC_INFO_TYPE_TARGET);
   isec->sec_info_type = SEC_INFO_TYPE_TARGET;
 
              || isec->sec_info_type == SEC_INFO_TYPE_TARGET);
   isec->sec_info_type = SEC_INFO_TYPE_TARGET;
 
-  if (htab->params->ppc476_workaround)
+  if (htab->params->ppc476_workaround
+      || htab->params->pic_fixup > 0)
     {
       if (elf_section_data (isec)->sec_info == NULL)
        {
     {
       if (elf_section_data (isec)->sec_info == NULL)
        {
@@ -6767,8 +6832,9 @@ ppc_elf_relax_section (bfd *abfd,
     trampoff += 4;
 
   symtab_hdr = &elf_symtab_hdr (abfd);
     trampoff += 4;
 
   symtab_hdr = &elf_symtab_hdr (abfd);
-
-  if (htab->params->branch_trampolines)
+  picfixup_size = 0;
+  if (htab->params->branch_trampolines
+      || htab->params->pic_fixup > 0)
     {
       /* Get a copy of the native relocations.  */
       if (isec->reloc_count != 0)
     {
       /* Get a copy of the native relocations.  */
       if (isec->reloc_count != 0)
@@ -6787,9 +6853,9 @@ ppc_elf_relax_section (bfd *abfd,
          unsigned long r_type = ELF32_R_TYPE (irel->r_info);
          bfd_vma toff, roff;
          asection *tsec;
          unsigned long r_type = ELF32_R_TYPE (irel->r_info);
          bfd_vma toff, roff;
          asection *tsec;
-         struct one_fixup *f;
+         struct one_branch_fixup *f;
          size_t insn_offset = 0;
          size_t insn_offset = 0;
-         bfd_vma max_branch_offset, val;
+         bfd_vma max_branch_offset = 0, val;
          bfd_byte *hit_addr;
          unsigned long t0;
          struct elf_link_hash_entry *h;
          bfd_byte *hit_addr;
          unsigned long t0;
          struct elf_link_hash_entry *h;
@@ -6810,6 +6876,11 @@ ppc_elf_relax_section (bfd *abfd,
              max_branch_offset = 1 << 15;
              break;
 
              max_branch_offset = 1 << 15;
              break;
 
+           case R_PPC_ADDR16_HA:
+             if (htab->params->pic_fixup > 0)
+               break;
+             continue;
+
            default:
              continue;
            }
            default:
              continue;
            }
@@ -6867,7 +6938,7 @@ ppc_elf_relax_section (bfd *abfd,
                       || h->root.type == bfd_link_hash_undefweak)
                {
                  tsec = bfd_und_section_ptr;
                       || h->root.type == bfd_link_hash_undefweak)
                {
                  tsec = bfd_und_section_ptr;
-                 toff = link_info->relocatable ? indx : 0;
+                 toff = bfd_link_relocatable (link_info) ? indx : 0;
                }
              else
                continue;
                }
              else
                continue;
@@ -6875,8 +6946,8 @@ ppc_elf_relax_section (bfd *abfd,
              /* If this branch is to __tls_get_addr then we may later
                 optimise away the call.  We won't be needing a long-
                 branch stub in that case.  */
              /* If this branch is to __tls_get_addr then we may later
                 optimise away the call.  We won't be needing a long-
                 branch stub in that case.  */
-             if (link_info->executable
-                 && !link_info->relocatable
+             if (bfd_link_executable (link_info)
+                 && !bfd_link_relocatable (link_info)
                  && h == htab->tls_get_addr
                  && irel != internal_relocs)
                {
                  && h == htab->tls_get_addr
                  && irel != internal_relocs)
                {
@@ -6931,6 +7002,17 @@ ppc_elf_relax_section (bfd *abfd,
              sym_type = h->type;
            }
 
              sym_type = h->type;
            }
 
+         if (r_type == R_PPC_ADDR16_HA)
+           {
+             if (h != NULL
+                 && !h->def_regular
+                 && h->protected_def
+                 && ppc_elf_hash_entry (h)->has_addr16_ha
+                 && ppc_elf_hash_entry (h)->has_addr16_lo)
+               picfixup_size += 12;
+             continue;
+           }
+
          /* The condition here under which we call find_plt_ent must
             match that in relocate_section.  If we call find_plt_ent here
             but not in relocate_section, or vice versa, then the branch
          /* The condition here under which we call find_plt_ent must
             match that in relocate_section.  If we call find_plt_ent here
             but not in relocate_section, or vice versa, then the branch
@@ -6956,7 +7038,7 @@ ppc_elf_relax_section (bfd *abfd,
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
-             if (r_type == R_PPC_PLTREL24 && link_info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info))
                addend = irel->r_addend;
              ent = find_plt_ent (plist, got2, addend);
              if (ent != NULL)
                addend = irel->r_addend;
              ent = find_plt_ent (plist, got2, addend);
              if (ent != NULL)
@@ -7022,7 +7104,7 @@ ppc_elf_relax_section (bfd *abfd,
            toff += irel->r_addend;
 
          /* Attempted -shared link of non-pic code loses.  */
            toff += irel->r_addend;
 
          /* Attempted -shared link of non-pic code loses.  */
-         if ((!link_info->relocatable
+         if ((!bfd_link_relocatable (link_info)
               && tsec == bfd_und_section_ptr)
              || tsec->output_section == NULL
              || (tsec->owner != NULL
               && tsec == bfd_und_section_ptr)
              || tsec->output_section == NULL
              || (tsec->owner != NULL
@@ -7033,7 +7115,7 @@ ppc_elf_relax_section (bfd *abfd,
 
          /* If the branch is in range, no need to do anything.  */
          if (tsec != bfd_und_section_ptr
 
          /* If the branch is in range, no need to do anything.  */
          if (tsec != bfd_und_section_ptr
-             && (!link_info->relocatable
+             && (!bfd_link_relocatable (link_info)
                  /* A relocatable link may have sections moved during
                     final link, so do not presume they remain in range.  */
                  || tsec->output_section == isec->output_section))
                  /* A relocatable link may have sections moved during
                     final link, so do not presume they remain in range.  */
                  || tsec->output_section == isec->output_section))
@@ -7048,7 +7130,7 @@ ppc_elf_relax_section (bfd *abfd,
            }
 
          /* Look for an existing fixup to this address.  */
            }
 
          /* Look for an existing fixup to this address.  */
-         for (f = fixups; f ; f = f->next)
+         for (f = branch_fixups; f ; f = f->next)
            if (f->tsec == tsec && f->toff == toff)
              break;
 
            if (f->tsec == tsec && f->toff == toff)
              break;
 
@@ -7063,7 +7145,7 @@ ppc_elf_relax_section (bfd *abfd,
                   one.  We'll report an error later.  */
                continue;
 
                   one.  We'll report an error later.  */
                continue;
 
-             if (link_info->shared)
+             if (bfd_link_pic (link_info))
                {
                  size = 4 * ARRAY_SIZE (shared_stub_entry);
                  insn_offset = 12;
                {
                  size = 4 * ARRAY_SIZE (shared_stub_entry);
                  insn_offset = 12;
@@ -7093,11 +7175,11 @@ ppc_elf_relax_section (bfd *abfd,
 
              /* Record the fixup so we don't do it again this section.  */
              f = bfd_malloc (sizeof (*f));
 
              /* Record the fixup so we don't do it again this section.  */
              f = bfd_malloc (sizeof (*f));
-             f->next = fixups;
+             f->next = branch_fixups;
              f->tsec = tsec;
              f->toff = toff;
              f->trampoff = trampoff;
              f->tsec = tsec;
              f->toff = toff;
              f->trampoff = trampoff;
-             fixups = f;
+             branch_fixups = f;
 
              trampoff += size;
              changes++;
 
              trampoff += size;
              changes++;
@@ -7147,10 +7229,10 @@ ppc_elf_relax_section (bfd *abfd,
            }
        }
 
            }
        }
 
-      while (fixups != NULL)
+      while (branch_fixups != NULL)
        {
        {
-         struct one_fixup *f = fixups;
-         fixups = fixups->next;
+         struct one_branch_fixup *f = branch_fixups;
+         branch_fixups = branch_fixups->next;
          free (f);
        }
     }
          free (f);
        }
     }
@@ -7158,7 +7240,7 @@ ppc_elf_relax_section (bfd *abfd,
   workaround_change = FALSE;
   newsize = trampoff;
   if (htab->params->ppc476_workaround
   workaround_change = FALSE;
   newsize = trampoff;
   if (htab->params->ppc476_workaround
-      && (!link_info->relocatable
+      && (!bfd_link_relocatable (link_info)
          || isec->output_section->alignment_power >= htab->params->pagesize_p2))
     {
       bfd_vma addr, end_addr;
          || isec->output_section->alignment_power >= htab->params->pagesize_p2))
     {
       bfd_vma addr, end_addr;
@@ -7187,7 +7269,15 @@ ppc_elf_relax_section (bfd *abfd,
       newsize = trampoff + relax_info->workaround_size;
     }
 
       newsize = trampoff + relax_info->workaround_size;
     }
 
-  if (changes || workaround_change)
+  if (htab->params->pic_fixup > 0)
+    {
+      picfixup_size -= relax_info->picfixup_size;
+      if (picfixup_size != 0)
+       relax_info->picfixup_size += picfixup_size;
+      newsize += relax_info->picfixup_size;
+    }
+
+  if (changes != 0 || picfixup_size != 0 || workaround_change)
     isec->size = newsize;
 
   if (isymbuf != NULL
     isec->size = newsize;
 
   if (isymbuf != NULL
@@ -7214,6 +7304,7 @@ ppc_elf_relax_section (bfd *abfd,
        }
     }
 
        }
     }
 
+  changes += picfixup_size;
   if (changes != 0)
     {
       /* Append sufficient NOP relocs so we can write out relocation
   if (changes != 0)
     {
       /* Append sufficient NOP relocs so we can write out relocation
@@ -7248,10 +7339,10 @@ ppc_elf_relax_section (bfd *abfd,
   return TRUE;
 
  error_return:
   return TRUE;
 
  error_return:
-  while (fixups != NULL)
+  while (branch_fixups != NULL)
     {
     {
-      struct one_fixup *f = fixups;
-      fixups = fixups->next;
+      struct one_branch_fixup *f = branch_fixups;
+      branch_fixups = branch_fixups->next;
       free (f);
     }
   if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
       free (f);
     }
   if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
@@ -7357,7 +7448,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
         + plt_sec->output_section->vma
         + plt_sec->output_offset);
 
         + plt_sec->output_section->vma
         + plt_sec->output_offset);
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       bfd_vma got = 0;
 
     {
       bfd_vma got = 0;
 
@@ -7567,13 +7658,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
   bfd_boolean ret = TRUE;
   bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
   bfd_boolean is_vxworks_tls;
   bfd_boolean ret = TRUE;
   bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
   bfd_boolean is_vxworks_tls;
+  unsigned int picfixup_size = 0;
+  struct ppc_elf_relax_info *relax_info = NULL;
 
 #ifdef DEBUG
   _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
                      "%ld relocations%s",
                      input_bfd, input_section,
                      (long) input_section->reloc_count,
 
 #ifdef DEBUG
   _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
                      "%ld relocations%s",
                      input_bfd, input_section,
                      (long) input_section->reloc_count,
-                     (info->relocatable) ? " (relocatable)" : "");
+                     (bfd_link_relocatable (info)) ? " (relocatable)" : "");
 #endif
 
   got2 = bfd_get_section_by_name (input_bfd, ".got2");
 #endif
 
   got2 = bfd_get_section_by_name (input_bfd, ".got2");
@@ -7588,9 +7681,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
   sym_hashes = elf_sym_hashes (input_bfd);
   /* We have to handle relocations in vxworks .tls_vars sections
      specially, because the dynamic loader is 'weird'.  */
   sym_hashes = elf_sym_hashes (input_bfd);
   /* We have to handle relocations in vxworks .tls_vars sections
      specially, because the dynamic loader is 'weird'.  */
-  is_vxworks_tls = (htab->is_vxworks && info->shared
+  is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
                    && !strcmp (input_section->output_section->name,
                                ".tls_vars"));
                    && !strcmp (input_section->output_section->name,
                                ".tls_vars"));
+  if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
+    relax_info = elf_section_data (input_section)->sec_info;
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
@@ -7652,7 +7747,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                           rel, 1, relend, howto, 0, contents);
        }
 
                                           rel, 1, relend, howto, 0, contents);
        }
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        {
          if (got2 != NULL
              && r_type == R_PPC_PLTREL24
        {
          if (got2 != NULL
              && r_type == R_PPC_PLTREL24
@@ -7754,8 +7849,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          + R_PPC_GOT_TPREL16);
              else
                {
                          + R_PPC_GOT_TPREL16);
              else
                {
-                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
                  rel->r_offset -= d_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);
                  r_type = R_PPC_NONE;
                }
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -7788,12 +7883,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;
                  && 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 */
              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)
                    {
                  insn1 |= 32 << 26;    /* lwz */
                  if (offset != (bfd_vma) -1)
                    {
@@ -7808,7 +7907,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              else
                {
                  /* LE */
              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.  */
                  if (tls_gd == 0)
                    {
                      /* Was an LD reloc.  */
@@ -7943,6 +8043,114 @@ ppc_elf_relocate_section (bfd *output_bfd,
          }
        }
 
          }
        }
 
+      if (ELIMINATE_COPY_RELOCS
+         && h != NULL
+         && !h->def_regular
+         && h->protected_def
+         && ppc_elf_hash_entry (h)->has_addr16_ha
+         && ppc_elf_hash_entry (h)->has_addr16_lo
+         && htab->params->pic_fixup > 0)
+       {
+         /* Convert lis;addi or lis;load/store accessing a protected
+            variable defined in a shared library to PIC.  */
+         unsigned int insn;
+
+         if (r_type == R_PPC_ADDR16_HA)
+           {
+             insn = bfd_get_32 (output_bfd,
+                                contents + rel->r_offset - d_offset);
+             if ((insn & (0x3f << 26)) == (15u << 26)
+                 && (insn & (0x1f << 16)) == 0 /* lis */)
+               {
+                 bfd_byte *p;
+                 bfd_vma off;
+                 bfd_vma got_addr;
+
+                 p = (contents + input_section->size
+                      - relax_info->workaround_size
+                      - relax_info->picfixup_size
+                      + picfixup_size);
+                 off = (p - contents) - (rel->r_offset - d_offset);
+                 if (off > 0x1fffffc || (off & 3) != 0)
+                   info->callbacks->einfo
+                     (_("%P: %H: fixup branch overflow\n"),
+                      input_bfd, input_section, rel->r_offset);
+
+                 bfd_put_32 (output_bfd, B | off,
+                             contents + rel->r_offset - d_offset);
+                 got_addr = (htab->got->output_section->vma
+                             + htab->got->output_offset
+                             + (h->got.offset & ~1));
+                 rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
+                 rel->r_addend = got_addr;
+                 rel->r_offset = (p - contents) + d_offset;
+                 insn &= ~0xffff;
+                 insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+                 bfd_put_32 (output_bfd, insn, p);
+
+                 /* Convert lis to lwz, loading address from GOT.  */
+                 insn &= ~0xffff;
+                 insn ^= (32u ^ 15u) << 26;
+                 insn |= (insn & (0x1f << 21)) >> 5;
+                 insn |= got_addr & 0xffff;
+                 bfd_put_32 (output_bfd, insn, p + 4);
+
+                 bfd_put_32 (output_bfd, B | ((-4 - off) & 0x3ffffff), p + 8);
+                 picfixup_size += 12;
+
+                 /* Use one of the spare relocs, so --emit-relocs
+                    output is reasonable.  */
+                 memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
+                 rel++;
+                 rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO);
+                 rel->r_offset += 4;
+
+                 /* Continue on as if we had a got reloc, to output
+                    dynamic reloc.  */
+                 r_type = R_PPC_GOT16_LO;
+               }
+             else
+               info->callbacks->einfo
+                 (_("%P: %H: error: %s with unexpected instruction %x\n"),
+                  input_bfd, input_section, rel->r_offset,
+                  "R_PPC_ADDR16_HA", insn);
+           }
+         else if (r_type == R_PPC_ADDR16_LO)
+           {
+             insn = bfd_get_32 (output_bfd,
+                                contents + rel->r_offset - d_offset);
+             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)))
+               {
+                 /* Arrange to apply the reloc addend, if any.  */
+                 relocation = 0;
+                 unresolved_reloc = FALSE;
+                 rel->r_info = ELF32_R_INFO (0, r_type);
+               }
+             else
+               info->callbacks->einfo
+                 (_("%P: %H: error: %s with unexpected instruction %x\n"),
+                  input_bfd, input_section, rel->r_offset,
+                  "R_PPC_ADDR16_LO", insn);
+           }
+       }
+
       ifunc = NULL;
       if (!htab->is_vxworks)
        {
       ifunc = NULL;
       if (!htab->is_vxworks)
        {
@@ -7965,11 +8173,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
          ent = NULL;
          if (ifunc != NULL
 
          ent = NULL;
          if (ifunc != NULL
-             && (!info->shared
+             && (!bfd_link_pic (info)
                  || is_branch_reloc (r_type)))
            {
              addend = 0;
                  || is_branch_reloc (r_type)))
            {
              addend = 0;
-             if (r_type == R_PPC_PLTREL24 && info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
            }
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
            }
@@ -8097,8 +8305,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              {
                bfd_boolean dyn;
                dyn = htab->elf.dynamic_sections_created;
              {
                bfd_boolean dyn;
                dyn = htab->elf.dynamic_sections_created;
-               if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-                   || (info->shared
+               if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+                   || (bfd_link_pic (info)
                        && SYMBOL_REFERENCES_LOCAL (info, h)))
                  /* This is actually a static link, or it is a
                     -Bsymbolic link and the symbol is defined
                        && SYMBOL_REFERENCES_LOCAL (info, h)))
                  /* This is actually a static link, or it is a
                     -Bsymbolic link and the symbol is defined
@@ -8166,7 +8374,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      }
 
                    /* Generate relocs for the dynamic linker.  */
                      }
 
                    /* Generate relocs for the dynamic linker.  */
-                   if ((info->shared || indx != 0)
+                   if ((bfd_link_pic (info) || indx != 0)
                        && (offp == &htab->tlsld_got.offset
                            || h == NULL
                            || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                        && (offp == &htab->tlsld_got.offset
                            || h == NULL
                            || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
@@ -8210,7 +8418,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          {
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
                          {
                            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++
                          }
                        loc = rsec->contents;
                        loc += (rsec->reloc_count++
@@ -8228,9 +8441,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          value = 1;
                        else if (tls_ty != 0)
                          {
                          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))
                              {
 
                            if (tls_ty == (TLS_TLS | TLS_GD))
                              {
@@ -8277,6 +8495,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  }
              }
 
                  }
              }
 
+           /* If here for a picfixup, we're done.  */
+           if (r_type != ELF32_R_TYPE (rel->r_info))
+             continue;
+
            relocation = (htab->got->output_section->vma
                          + htab->got->output_offset
                          + off
            relocation = (htab->got->output_section->vma
                          + htab->got->output_offset
                          + off
@@ -8316,7 +8538,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_DTPREL16_LO:
        case R_PPC_DTPREL16_HI:
        case R_PPC_DTPREL16_HA:
        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
          break;
 
          /* Relocations that may need to be propagated if this is a shared
@@ -8340,18 +8563,21 @@ ppc_elf_relocate_section (bfd *output_bfd,
                bfd_put_32 (output_bfd, insn, p);
              break;
            }
                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:
          /* 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:
          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:
          goto dodyn;
 
        case R_PPC_DTPMOD32:
@@ -8397,7 +8623,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_ADDR14:
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_ADDR14:
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            break;
          /* fall through */
 
            break;
          /* fall through */
 
@@ -8406,7 +8632,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              || is_vxworks_tls)
            break;
 
              || is_vxworks_tls)
            break;
 
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && !(h != NULL
                    && ((h->root.type == bfd_link_hash_undefined
                         && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
               && !(h != NULL
                    && ((h->root.type == bfd_link_hash_undefined
                         && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
@@ -8416,11 +8642,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
               && (must_be_dyn_reloc (info, r_type)
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
               && (must_be_dyn_reloc (info, r_type)
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && h->dynindx != -1
                  && !h->non_got_ref
                  && h != NULL
                  && h->dynindx != -1
                  && !h->non_got_ref
-                 && !h->def_regular))
+                 && !h->def_regular
+                 && !(h->protected_def
+                      && ppc_elf_hash_entry (h)->has_addr16_ha
+                      && ppc_elf_hash_entry (h)->has_addr16_lo
+                      && htab->params->pic_fixup > 0)))
            {
              int skip;
              bfd_byte *loc;
            {
              int skip;
              bfd_byte *loc;
@@ -8563,7 +8793,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
              if (r_type == R_PPC_RELAX_PLTREL24)
                {
 
              if (r_type == R_PPC_RELAX_PLTREL24)
                {
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    got2_addend = addend;
                  addend = 0;
                }
                    got2_addend = addend;
                  addend = 0;
                }
@@ -8586,7 +8816,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
            size_t insn_offset = rel->r_offset;
            unsigned int insn;
 
            size_t insn_offset = rel->r_offset;
            unsigned int insn;
 
-           if (info->shared)
+           if (bfd_link_pic (info))
              {
                relocation -= (input_section->output_section->vma
                               + input_section->output_offset
              {
                relocation -= (input_section->output_section->vma
                               + input_section->output_offset
@@ -8605,7 +8835,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
 
            relocation += addend;
              }
 
            relocation += addend;
-           if (info->relocatable)
+           if (bfd_link_relocatable (info))
              relocation = 0;
 
            /* First insn is HA, second is LO.  */
              relocation = 0;
 
            /* First insn is HA, second is LO.  */
@@ -8691,7 +8921,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (h != NULL && ifunc == NULL)
            {
              struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
          if (h != NULL && ifunc == NULL)
            {
              struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   info->shared ? addend : 0);
+                                                   bfd_link_pic (info) ? addend : 0);
              if (ent == NULL
                  || htab->plt == NULL)
                {
              if (ent == NULL
                  || htab->plt == NULL)
                {
@@ -9199,30 +9429,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (r == bfd_reloc_overflow)
            {
            overflow:
          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
            {
            }
          else
            {
@@ -9251,15 +9471,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
   if (htab->params->ppc476_workaround
       && input_section->sec_info_type == SEC_INFO_TYPE_TARGET
 
   if (htab->params->ppc476_workaround
       && input_section->sec_info_type == SEC_INFO_TYPE_TARGET
-      && (!info->relocatable
+      && (!bfd_link_relocatable (info)
          || (input_section->output_section->alignment_power
              >= htab->params->pagesize_p2)))
     {
          || (input_section->output_section->alignment_power
              >= htab->params->pagesize_p2)))
     {
-      struct ppc_elf_relax_info *relax_info;
       bfd_vma start_addr, end_addr, addr;
       bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
 
       bfd_vma start_addr, end_addr, addr;
       bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
 
-      relax_info = elf_section_data (input_section)->sec_info;
       if (relax_info->workaround_size != 0)
        {
          bfd_byte *p;
       if (relax_info->workaround_size != 0)
        {
          bfd_byte *p;
@@ -9363,13 +9581,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
             prevent the bad prefetch from happening in the first
             place:
             .
             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                   
+            .  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
             .  nop                      b somewhere_else
-            .  b somewhere_else         nop                    
-            . new_page:                new_page:               
+            .  b somewhere_else         nop
+            . new_page:                new_page:
             .  */
          insn = bfd_get_32 (input_bfd, contents + offset);
          if ((insn & (0x3f << 26)) == (18u << 26)          /* b,bl,ba,bla */
             .  */
          insn = bfd_get_32 (input_bfd, contents + offset);
          if ((insn & (0x3f << 26)) == (18u << 26)          /* b,bl,ba,bla */
@@ -9390,6 +9608,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              && rel->r_offset >= offset
              && rel->r_offset < offset + 4)
            {
              && rel->r_offset >= offset
              && rel->r_offset < offset + 4)
            {
+             asection *sreloc;
+
              /* If the insn we are patching had a reloc, adjust the
                 reloc r_offset so that the reloc applies to the moved
                 location.  This matters for -r and --emit-relocs.  */
              /* If the insn we are patching had a reloc, adjust the
                 reloc r_offset so that the reloc applies to the moved
                 location.  This matters for -r and --emit-relocs.  */
@@ -9402,6 +9622,57 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  relend[-1] = tmp;
                }
              relend[-1].r_offset += patch_off - offset;
                  relend[-1] = tmp;
                }
              relend[-1].r_offset += patch_off - offset;
+
+             /* Adjust REL16 addends too.  */
+             switch (ELF32_R_TYPE (relend[-1].r_info))
+               {
+               case R_PPC_REL16:
+               case R_PPC_REL16_LO:
+               case R_PPC_REL16_HI:
+               case R_PPC_REL16_HA:
+                 relend[-1].r_addend += patch_off - offset;
+                 break;
+               default:
+                 break;
+               }
+
+             /* If we are building a PIE or shared library with
+                non-PIC objects, perhaps we had a dynamic reloc too?
+                If so, the dynamic reloc must move with the insn.  */
+             sreloc = elf_section_data (input_section)->sreloc;
+             if (sreloc != NULL)
+               {
+                 Elf32_External_Rela *slo, *shi, *srelend;
+                 bfd_vma soffset;
+
+                 slo = (Elf32_External_Rela *) sreloc->contents;
+                 shi = srelend = slo + sreloc->reloc_count;
+                 soffset = (offset + input_section->output_section->vma
+                            + input_section->output_offset);
+                 while (slo < shi)
+                   {
+                     Elf32_External_Rela *srel = slo + (shi - slo) / 2;
+                     bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel,
+                                               &outrel);
+                     if (outrel.r_offset < soffset)
+                       slo = srel + 1;
+                     else if (outrel.r_offset > soffset + 3)
+                       shi = srel;
+                     else
+                       {
+                         if (srel + 1 != srelend)
+                           {
+                             memmove (srel, srel + 1,
+                                      (srelend - (srel + 1)) * sizeof (*srel));
+                             srel = srelend - 1;
+                           }
+                         outrel.r_offset += patch_off - offset;
+                         bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+                                                    (bfd_byte *) srel);
+                         break;
+                       }
+                   }
+               }
            }
          else
            rel = NULL;
            }
          else
            rel = NULL;
@@ -9412,9 +9683,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
              bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
 
              delta += offset - patch_off;
              bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
 
              delta += offset - patch_off;
-             if (info->relocatable && rel != NULL)
+             if (bfd_link_relocatable (info) && rel != NULL)
                delta = 0;
                delta = 0;
-             if (!info->relocatable && rel != NULL)
+             if (!bfd_link_relocatable (info) && rel != NULL)
                {
                  enum elf_ppc_reloc_type r_type;
 
                {
                  enum elf_ppc_reloc_type r_type;
 
@@ -9540,11 +9811,11 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                got_offset = (reloc_index + 3) * 4;
 
                /* Use the right PLT. */
                got_offset = (reloc_index + 3) * 4;
 
                /* Use the right PLT. */
-               plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry
+               plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry
                            : ppc_elf_vxworks_plt_entry;
 
                /* Fill in the .plt on VxWorks.  */
                            : ppc_elf_vxworks_plt_entry;
 
                /* Fill in the .plt on VxWorks.  */
-               if (info->shared)
+               if (bfd_link_pic (info))
                  {
                    bfd_put_32 (output_bfd,
                                plt_entry[0] | PPC_HA (got_offset),
                  {
                    bfd_put_32 (output_bfd,
                                plt_entry[0] | PPC_HA (got_offset),
@@ -9602,7 +9873,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                                         + ent->plt.offset + 16),
                            htab->sgotplt->contents + got_offset);
 
                                         + ent->plt.offset + 16),
                            htab->sgotplt->contents + got_offset);
 
-               if (!info->shared)
+               if (!bfd_link_pic (info))
                  {
                    /* Fill in a couple of entries in .rela.plt.unloaded.  */
                    loc = htab->srelplt2->contents
                  {
                    /* Fill in a couple of entries in .rela.plt.unloaded.  */
                    loc = htab->srelplt2->contents
@@ -9724,7 +9995,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                  }
              }
            else if (h->type == STT_GNU_IFUNC
                  }
              }
            else if (h->type == STT_GNU_IFUNC
-                    && !info->shared)
+                    && !bfd_link_pic (info))
              {
                /* Set the value of ifunc symbols in a non-pie
                   executable to the glink entry.  This is to avoid
              {
                /* Set the value of ifunc symbols in a non-pie
                   executable to the glink entry.  This is to avoid
@@ -9776,7 +10047,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
            write_glink_stub (ent, splt, p, info);
 
 
            write_glink_stub (ent, splt, p, info);
 
-           if (!info->shared)
+           if (!bfd_link_pic (info))
              /* We only need one non-PIC glink stub.  */
              break;
          }
              /* We only need one non-PIC glink stub.  */
              break;
          }
@@ -9971,11 +10242,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   if (splt && splt->size > 0)
     {
       /* Use the right PLT. */
   if (splt && splt->size > 0)
     {
       /* Use the right PLT. */
-      const bfd_vma *plt_entry = (info->shared
+      const bfd_vma *plt_entry = (bfd_link_pic (info)
                                  ? ppc_elf_vxworks_pic_plt0_entry
                                  : ppc_elf_vxworks_plt0_entry);
 
                                  ? ppc_elf_vxworks_pic_plt0_entry
                                  : ppc_elf_vxworks_plt0_entry);
 
-      if (!info->shared)
+      if (!bfd_link_pic (info))
        {
          bfd_vma got_value = SYM_VAL (htab->elf.hgot);
 
        {
          bfd_vma got_value = SYM_VAL (htab->elf.hgot);
 
@@ -9996,7 +10267,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
       bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
 
       bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
       bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
 
-      if (! info->shared)
+      if (! bfd_link_pic (info))
        {
          Elf_Internal_Rela rela;
          bfd_byte *loc;
        {
          Elf_Internal_Rela rela;
          bfd_byte *loc;
@@ -10213,7 +10484,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
 
       /* Last comes the PLTresolve stub.  */
        }
 
       /* Last comes the PLTresolve stub.  */
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          bfd_vma bcl;
 
        {
          bfd_vma bcl;
 
@@ -10327,11 +10598,12 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define ELF_MACHINE_CODE       EM_PPC
 #ifdef __QNXTARGET__
 #define ELF_MAXPAGESIZE                0x1000
 #define ELF_MACHINE_CODE       EM_PPC
 #ifdef __QNXTARGET__
 #define ELF_MAXPAGESIZE                0x1000
+#define ELF_COMMONPAGESIZE     0x1000
 #else
 #define ELF_MAXPAGESIZE                0x10000
 #else
 #define ELF_MAXPAGESIZE                0x10000
+#define ELF_COMMONPAGESIZE     0x10000
 #endif
 #define ELF_MINPAGESIZE                0x1000
 #endif
 #define ELF_MINPAGESIZE                0x1000
-#define ELF_COMMONPAGESIZE     0x1000
 #define elf_info_to_howto      ppc_elf_info_to_howto
 
 #ifdef  EM_CYGNUS_POWERPC
 #define elf_info_to_howto      ppc_elf_info_to_howto
 
 #ifdef  EM_CYGNUS_POWERPC
This page took 0.04889 seconds and 4 git commands to generate.