Fix indentation of:
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 06b14768bb23776985d37c51ff62f805b8269156..c3b211528fe3c3a17429b43ecb4f535dab637104 100644 (file)
@@ -1,6 +1,6 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009 Free Software Foundation, Inc.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
    Largely rewritten by Alan Modra <amodra@bigpond.net.au>
@@ -92,7 +92,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
 #define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
 #define elf_backend_add_symbol_hook          ppc64_elf_add_symbol_hook
-#define elf_backend_check_directives         ppc64_elf_check_directives
+#define elf_backend_check_directives         ppc64_elf_process_dot_syms
 #define elf_backend_as_needed_cleanup        ppc64_elf_as_needed_cleanup
 #define elf_backend_archive_symbol_lookup     ppc64_elf_archive_symbol_lookup
 #define elf_backend_check_relocs             ppc64_elf_check_relocs
@@ -1235,7 +1235,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xfffc,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC64_TLS,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -1250,6 +1250,34 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC64_TLSGD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_TLSGD",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC64_TLSLD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_TLSLD",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC64_DTPMOD64,
@@ -2031,6 +2059,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC_TLS:                    r = R_PPC64_TLS;
       break;
+    case BFD_RELOC_PPC_TLSGD:                  r = R_PPC64_TLSGD;
+      break;
+    case BFD_RELOC_PPC_TLSLD:                  r = R_PPC64_TLSLD;
+      break;
     case BFD_RELOC_PPC_DTPMOD:                 r = R_PPC64_DTPMOD64;
       break;
     case BFD_RELOC_PPC_TPREL16:                        r = R_PPC64_TPREL16;
@@ -2608,9 +2640,15 @@ struct _ppc64_elf_section_data
       long *adjust;
     } opd;
 
-    /* An array for toc sections, indexed by offset/8.
-       Specifies the relocation symbol index used at a given toc offset.  */
-    unsigned *t_symndx;
+    /* An array for toc sections, indexed by offset/8.  */
+    struct _toc_sec_data
+    {
+      /* Specifies the relocation symbol index used at a given toc offset.  */
+      unsigned *symndx;
+
+      /* And the relocation addend.  */
+      bfd_vma *add;
+    } toc;
   } u;
 
   enum _ppc64_sec_type sec_type:2;
@@ -2651,7 +2689,6 @@ get_opd_info (asection * sec)
 }
 \f
 /* Parameters for the qsort hook.  */
-static asection *synthetic_opd;
 static bfd_boolean synthetic_relocatable;
 
 /* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
@@ -2669,9 +2706,11 @@ compare_symbols (const void *ap, const void *bp)
     return 1;
 
   /* then .opd symbols.  */
-  if (a->section == synthetic_opd && b->section != synthetic_opd)
+  if (strcmp (a->section->name, ".opd") == 0
+      && strcmp (b->section->name, ".opd") != 0)
     return -1;
-  if (a->section != synthetic_opd && b->section == synthetic_opd)
+  if (strcmp (a->section->name, ".opd") != 0
+      && strcmp (b->section->name, ".opd") == 0)
     return 1;
 
   /* then other code symbols.  */
@@ -2825,7 +2864,6 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   else
     memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
-  synthetic_opd = opd;
   synthetic_relocatable = relocatable;
   qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
@@ -2843,7 +2881,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
     }
 
   i = 0;
-  if (syms[i]->section == opd)
+  if (strcmp (syms[i]->section->name, ".opd") == 0)
     ++i;
   codesecsym = i;
 
@@ -2860,7 +2898,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   secsymend = i;
 
   for (; i < symcount; ++i)
-    if (syms[i]->section != opd)
+    if (strcmp (syms[i]->section->name, ".opd") != 0)
       break;
   opdsymend = i;
 
@@ -2954,6 +2992,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
              size_t len;
 
              *s = *syms[i];
+             s->flags |= BSF_SYNTHETIC;
              s->section = sym->section;
              s->value = sym->value + r->addend;
              s->name = names;
@@ -2994,6 +3033,10 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
        {
          bfd_vma ent;
 
+         /* Ignore bogus symbols.  */
+         if (syms[i]->value > opd->size - 8)
+           continue;
+
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
@@ -3004,8 +3047,8 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
        }
 
       /* Get start of .glink stubs from DT_PPC64_GLINK.  */
-      dynamic = bfd_get_section_by_name (abfd, ".dynamic");
-      if (dynamic != NULL)
+      if (dyn_count != 0
+         && (dynamic = bfd_get_section_by_name (abfd, ".dynamic")) != NULL)
        {
          bfd_byte *dynbuf, *extdyn, *extdynend;
          size_t extdynsize;
@@ -3060,21 +3103,21 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
          if (resolv_vma)
            size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
-       }
 
-      relplt = bfd_get_section_by_name (abfd, ".rela.plt");
-      if (glink != NULL && relplt != NULL)
-       {
-         slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
-         if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
-           goto free_contents_and_exit;
+         relplt = bfd_get_section_by_name (abfd, ".rela.plt");
+         if (relplt != NULL)
+           {
+             slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+             if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
+               goto free_contents_and_exit;
        
-         plt_count = relplt->size / sizeof (Elf64_External_Rela);
-         size += plt_count * sizeof (asymbol);
+             plt_count = relplt->size / sizeof (Elf64_External_Rela);
+             size += plt_count * sizeof (asymbol);
 
-         p = relplt->relocation;
-         for (i = 0; i < plt_count; i++, p++)
-           size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+             p = relplt->relocation;
+             for (i = 0; i < plt_count; i++, p++)
+               size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+           }
        }
 
       s = *ret = bfd_malloc (size);
@@ -3087,6 +3130,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
        {
          bfd_vma ent;
 
+         if (syms[i]->value > opd->size - 8)
+           continue;
+
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
@@ -3124,6 +3170,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
                  if ((sec->flags & SEC_CODE) != 0)
                    s->section = sec;
                }
+             s->flags |= BSF_SYNTHETIC;
              s->value = ent - s->section->vma;
              s->name = names;
              *names++ = '.';
@@ -3145,7 +3192,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
              /* Add a symbol for the main glink trampoline.  */
              memset (s, 0, sizeof *s);
              s->the_bfd = abfd;
-             s->flags = BSF_GLOBAL;
+             s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
              s->section = glink;
              s->value = resolv_vma - glink->vma;
              s->name = names;
@@ -3181,6 +3228,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
                 we are defining a symbol, ensure one of them is set.  */
              if ((s->flags & BSF_LOCAL) == 0)
                s->flags |= BSF_GLOBAL;
+             s->flags |= BSF_SYNTHETIC;
              s->section = glink;
              s->value = glink_vma - glink->vma;
              s->name = names;
@@ -3617,14 +3665,14 @@ struct ppc_link_hash_table
   /* Set on error.  */
   unsigned int stub_error:1;
 
-  /* Temp used by ppc64_elf_check_directives.  */
+  /* Temp used by ppc64_elf_process_dot_syms.  */
   unsigned int twiddled_syms:1;
 
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
 };
 
 /* Rename some of the generic section flags to better document how they
@@ -4435,7 +4483,7 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
 /* Process list of dot-symbols we made in link_hash_newfunc.  */
 
 static bfd_boolean
-ppc64_elf_check_directives (bfd *ibfd, struct bfd_link_info *info)
+ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry **p, *eh;
@@ -4575,6 +4623,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
   asection **opd_sym_map;
+  struct elf_link_hash_entry *tga, *dottga;
 
   if (info->relocatable)
     return TRUE;
@@ -4591,6 +4640,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   BFD_ASSERT (is_ppc64_elf (abfd));
 
   htab = ppc_hash_table (info);
+  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                             FALSE, FALSE, TRUE);
+  dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+                                FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
 
   sym_hashes = elf_sym_hashes (abfd);
@@ -4630,7 +4683,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       enum elf_ppc64_reloc_type r_type;
-      int tls_type = 0;
+      int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -4644,9 +4697,42 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      tls_type = 0;
       r_type = ELF64_R_TYPE (rel->r_info);
+      if (h != NULL && (h == tga || h == dottga))
+       switch (r_type)
+         {
+         default:
+           break;
+
+         case R_PPC64_REL24:
+         case R_PPC64_REL14:
+         case R_PPC64_REL14_BRTAKEN:
+         case R_PPC64_REL14_BRNTAKEN:
+         case R_PPC64_ADDR24:
+         case R_PPC64_ADDR14:
+         case R_PPC64_ADDR14_BRTAKEN:
+         case R_PPC64_ADDR14_BRNTAKEN:
+           if (rel != relocs
+               && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+                   || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+             /* We have a new-style __tls_get_addr call with a marker
+                reloc.  */
+             ;
+           else
+             /* Mark this section as having an old-style call.  */
+             sec->has_tls_get_addr_call = 1;
+           break;
+         }
+
       switch (r_type)
        {
+       case R_PPC64_TLSGD:
+       case R_PPC64_TLSLD:
+         /* These special tls relocs tie a call to __tls_get_addr with
+            its parameter symbol.  */
+         break;
+
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_HI:
@@ -4811,8 +4897,17 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  dest = h->root.u.def.section;
              }
            else
-             dest = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                               sec, r_symndx);
+             {
+               Elf_Internal_Sym *isym;
+
+               isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                             abfd, r_symndx);
+               if (isym == NULL)
+                 return FALSE;
+
+               dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
+             }
+
            if (dest != sec)
              ppc64_elf_section_data (sec)->has_14bit_branch = 1;
          }
@@ -4826,25 +4921,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
                                    rel->r_addend))
                return FALSE;
-             if (h == &htab->tls_get_addr->elf
-                 || h == &htab->tls_get_addr_fd->elf)
+             if (h == tga || h == dottga)
                sec->has_tls_reloc = 1;
-             else if (htab->tls_get_addr == NULL
-                      && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr")
-                      && (h->root.root.string[15] == 0
-                          || h->root.root.string[15] == '@'))
-               {
-                 htab->tls_get_addr = (struct ppc_link_hash_entry *) h;
-                 sec->has_tls_reloc = 1;
-               }
-             else if (htab->tls_get_addr_fd == NULL
-                      && CONST_STRNEQ (h->root.root.string, "__tls_get_addr")
-                      && (h->root.root.string[14] == 0
-                          || h->root.root.string[14] == '@'))
-               {
-                 htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h;
-                 sec->has_tls_reloc = 1;
-               }
            }
          break;
 
@@ -4888,23 +4966,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          ppc64_sec = ppc64_elf_section_data (sec);
          if (ppc64_sec->sec_type != sec_toc)
            {
+             bfd_size_type amt;
+
              /* One extra to simplify get_tls_mask.  */
-             bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1;
-             ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt);
-             if (ppc64_sec->u.t_symndx == NULL)
+             amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
+             ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
+             if (ppc64_sec->u.toc.symndx == NULL)
+               return FALSE;
+             amt = sec->size * sizeof (bfd_vma) / 8;
+             ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
+             if (ppc64_sec->u.toc.add == NULL)
                return FALSE;
              BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
              ppc64_sec->sec_type = sec_toc;
            }
          BFD_ASSERT (rel->r_offset % 8 == 0);
-         ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx;
+         ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
+         ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
 
          /* Mark the second slot of a GD or LD entry.
             -1 to indicate GD and -2 to indicate LD.  */
          if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD))
-           ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1;
+           ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1;
          else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD))
-           ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2;
+           ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2;
          goto dodyn;
 
        case R_PPC64_TPREL16:
@@ -4942,12 +5027,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              else
                {
                  asection *s;
+                 Elf_Internal_Sym *isym;
 
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
-                                                r_symndx);
-                 if (s == NULL)
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
-                 else if (s != sec)
+
+                 s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                 if (s != NULL && s != sec)
                    opd_sym_map[rel->r_offset / 8] = s;
                }
            }
@@ -5025,43 +5113,11 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 this reloc.  */
              if (sreloc == NULL)
                {
-                 const char *name;
-                 bfd *dynobj;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return FALSE;
-
-                 if (! CONST_STRNEQ (name, ".rela")
-                     || strcmp (bfd_get_section_name (abfd, sec),
-                                name + 5) != 0)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%B: bad relocation section name `%s\'"),
-                        abfd, name);
-                     bfd_set_error (bfd_error_bad_value);
-                   }
+                 sreloc = _bfd_elf_make_dynamic_reloc_section
+                   (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
 
-                 dynobj = htab->elf.dynobj;
-                 sreloc = bfd_get_section_by_name (dynobj, name);
                  if (sreloc == NULL)
-                   {
-                     flagword flags;
-
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                              | SEC_ALLOC | SEC_LOAD);
-                     sreloc = bfd_make_section_with_flags (dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 3))
-                       return FALSE;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
+                   return FALSE;
                }
 
              /* If this is a global symbol, we count the number of
@@ -5075,15 +5131,19 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  /* Track dynamic relocs needed for local syms too.
                     We really need local syms available to do this
                     easily.  Oh well.  */
-
                  asection *s;
                  void *vpp;
+                 Elf_Internal_Sym *isym;
 
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                sec, r_symndx);
-                 if (s == NULL)
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
 
+                 s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                 if (s == NULL)
+                   s = sec;
+
                  vpp = &elf_section_data (s)->local_dynrel;
                  head = (struct ppc_dyn_relocs **) vpp;
                }
@@ -5844,7 +5904,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
 
   if (fdh == NULL
-      && info->shared
+      && !info->executable
       && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
     {
@@ -5877,7 +5937,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 
   if (fdh != NULL
       && !fdh->elf.forced_local
-      && (info->shared
+      && (!info->executable
          || fdh->elf.def_dynamic
          || fdh->elf.ref_dynamic
          || (fdh->elf.root.type == bfd_link_hash_undefweak
@@ -6255,9 +6315,12 @@ get_sym_h (struct elf_link_hash_entry **hp,
    type suitable for optimization, and 1 otherwise.  */
 
 static int
-get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
+get_tls_mask (char **tls_maskp,
+             unsigned long *toc_symndx,
+             bfd_vma *toc_addend,
              Elf_Internal_Sym **locsymsp,
-             const Elf_Internal_Rela *rel, bfd *ibfd)
+             const Elf_Internal_Rela *rel,
+             bfd *ibfd)
 {
   unsigned long r_symndx;
   int next_r;
@@ -6285,12 +6348,14 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
     off = sym->st_value;
   off += rel->r_addend;
   BFD_ASSERT (off % 8 == 0);
-  r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8];
-  next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1];
-  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
-    return 0;
+  r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8];
+  next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1];
   if (toc_symndx != NULL)
     *toc_symndx = r_symndx;
+  if (toc_addend != NULL)
+    *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
+  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
+    return 0;
   if ((h == NULL
        || ((h->root.type == bfd_link_hash_defined
            || h->root.type == bfd_link_hash_defweak)
@@ -6656,11 +6721,12 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
        {
          Elf_Internal_Rela *write_rel;
          bfd_byte *rptr, *wptr;
-         bfd_byte *new_contents = NULL;
+         bfd_byte *new_contents;
          bfd_boolean skip;
          long opd_ent_size;
          bfd_size_type amt;
 
+         new_contents = NULL;
          amt = sec->size * sizeof (long) / 8;
          opd = &ppc64_elf_section_data (sec)->u.opd;
          opd->adjust = bfd_zalloc (obfd, amt);
@@ -6895,36 +6961,49 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
   struct ppc_link_hash_table *htab;
 
   htab = ppc_hash_table (info);
-  if (htab->tls_get_addr != NULL)
-    {
-      struct ppc_link_hash_entry *h = htab->tls_get_addr;
-
-      while (h->elf.root.type == bfd_link_hash_indirect
-            || h->elf.root.type == bfd_link_hash_warning)
-       h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+  htab->tls_get_addr = ((struct ppc_link_hash_entry *)
+                       elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+                                             FALSE, FALSE, TRUE));
+  htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
+                          elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                                                FALSE, FALSE, TRUE));
+  return _bfd_elf_tls_setup (obfd, info);
+}
 
-      htab->tls_get_addr = h;
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+   HASH1 or HASH2.  */
 
-      if (htab->tls_get_addr_fd == NULL
-         && h->oh != NULL
-         && h->oh->is_func_descriptor
-         && (h->oh->elf.root.type == bfd_link_hash_defined
-             || h->oh->elf.root.type == bfd_link_hash_defweak))
-       htab->tls_get_addr_fd = h->oh;
-    }
-
-  if (htab->tls_get_addr_fd != NULL)
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+                        const Elf_Internal_Rela *rel,
+                        const struct ppc_link_hash_entry *hash1,
+                        const struct ppc_link_hash_entry *hash2)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+  enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
+  unsigned int r_symndx = ELF64_R_SYM (rel->r_info);
+
+  if (r_symndx >= symtab_hdr->sh_info
+      && (r_type == R_PPC64_REL24
+         || r_type == R_PPC64_REL14
+         || r_type == R_PPC64_REL14_BRTAKEN
+         || r_type == R_PPC64_REL14_BRNTAKEN
+         || r_type == R_PPC64_ADDR24
+         || r_type == R_PPC64_ADDR14
+         || r_type == R_PPC64_ADDR14_BRTAKEN
+         || r_type == R_PPC64_ADDR14_BRNTAKEN))
     {
-      struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;
-
-      while (h->elf.root.type == bfd_link_hash_indirect
-            || h->elf.root.type == bfd_link_hash_warning)
-       h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
 
-      htab->tls_get_addr_fd = h;
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      if (h == &hash1->elf || h == &hash2->elf)
+       return TRUE;
     }
-
-  return _bfd_elf_tls_setup (obfd, info);
+  return FALSE;
 }
 
 /* Run through all the TLS relocs looking for optimization
@@ -7082,6 +7161,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                    case R_PPC64_TOC16:
                    case R_PPC64_TOC16_LO:
                    case R_PPC64_TLS:
+                   case R_PPC64_TLSGD:
+                   case R_PPC64_TLSLD:
                      if (sym_sec == NULL || sym_sec != toc)
                        continue;
 
@@ -7102,7 +7183,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      value += rel->r_addend;
                      BFD_ASSERT (value < toc->size && value % 8 == 0);
                      toc_ref_index = value / 8;
-                     if (r_type == R_PPC64_TLS)
+                     if (r_type == R_PPC64_TLS
+                         || r_type == R_PPC64_TLSGD
+                         || r_type == R_PPC64_TLSLD)
                        {
                          toc_ref[toc_ref_index] = 1;
                          continue;
@@ -7167,58 +7250,30 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
 
                  if (pass == 0)
                    {
-                     if (!expecting_tls_get_addr)
+                     if (!expecting_tls_get_addr
+                         || !sec->has_tls_get_addr_call)
                        continue;
 
-                     if (rel + 1 < relend)
+                     if (rel + 1 < relend
+                         && branch_reloc_hash_match (ibfd, rel + 1,
+                                                     htab->tls_get_addr,
+                                                     htab->tls_get_addr_fd))
                        {
-                         Elf_Internal_Shdr *symtab_hdr;
-                         enum elf_ppc64_reloc_type r_type2;
-                         unsigned long r_symndx2;
-                         struct elf_link_hash_entry *h2;
-
-                         symtab_hdr = &elf_symtab_hdr (ibfd);
-
-                         /* The next instruction should be a call to
-                            __tls_get_addr.  Peek at the reloc to be sure.  */
-                         r_type2 = ELF64_R_TYPE (rel[1].r_info);
-                         r_symndx2 = ELF64_R_SYM (rel[1].r_info);
-                         if (r_symndx2 >= symtab_hdr->sh_info
-                             && (r_type2 == R_PPC64_REL14
-                                 || r_type2 == R_PPC64_REL14_BRTAKEN
-                                 || r_type2 == R_PPC64_REL14_BRNTAKEN
-                                 || r_type2 == R_PPC64_REL24))
+                         if (expecting_tls_get_addr == 2)
                            {
-                             struct elf_link_hash_entry **sym_hashes;
-
-                             sym_hashes = elf_sym_hashes (ibfd);
-
-                             h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
-                             while (h2->root.type == bfd_link_hash_indirect
-                                    || h2->root.type == bfd_link_hash_warning)
-                               h2 = ((struct elf_link_hash_entry *)
-                                     h2->root.u.i.link);
-                             if (h2 != NULL
-                                 && (h2 == &htab->tls_get_addr->elf
-                                     || h2 == &htab->tls_get_addr_fd->elf))
-                               {
-                                 if (expecting_tls_get_addr == 2)
-                                   {
-                                     /* Check for toc tls entries.  */
-                                     char *toc_tls;
-                                     int retval;
-
-                                     retval = get_tls_mask (&toc_tls, NULL,
-                                                            &locsyms,
-                                                            rel, ibfd);
-                                     if (retval == 0)
-                                       goto err_free_rel;
-                                     if (retval > 1 && toc_tls != NULL)
-                                       toc_ref[toc_ref_index] = 1;
-                                   }
-                                 continue;
-                               }
+                             /* Check for toc tls entries.  */
+                             char *toc_tls;
+                             int retval;
+
+                             retval = get_tls_mask (&toc_tls, NULL, NULL,
+                                                    &locsyms,
+                                                    rel, ibfd);
+                             if (retval == 0)
+                               goto err_free_rel;
+                             if (retval > 1 && toc_tls != NULL)
+                               toc_ref[toc_ref_index] = 1;
                            }
+                         continue;
                        }
 
                      if (expecting_tls_get_addr != 1)
@@ -7315,18 +7370,18 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                free (relstart);
            }
 
-       if (toc_ref != NULL)
-         free (toc_ref);
+      if (toc_ref != NULL)
+       free (toc_ref);
 
-       if (locsyms != NULL
-           && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
-         {
-           if (!info->keep_memory)
-             free (locsyms);
-           else
-             elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
-         }
-      }
+      if (locsyms != NULL
+         && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
+       {
+         if (!info->keep_memory)
+           free (locsyms);
+         else
+           elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
+       }
+    }
   return TRUE;
 }
 
@@ -7888,7 +7943,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
           Undefined weak syms won't yet be marked as dynamic,
           nor will all TLS symbols.  */
        if (h->dynindx == -1
-           && !h->forced_local)
+           && !h->forced_local
+           && htab->elf.dynamic_sections_created)
          {
            if (! bfd_elf_link_record_dynamic_symbol (info, h))
              return FALSE;
@@ -7922,7 +7978,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     else
       gent->got.offset = (bfd_vma) -1;
 
-  if (eh->dyn_relocs == NULL)
+  if (eh->dyn_relocs == NULL
+      || !htab->elf.dynamic_sections_created)
     return TRUE;
 
   /* In the shared -Bsymbolic case, discard space allocated for
@@ -7979,7 +8036,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         dynamic.  */
 
       if (!h->non_got_ref
-         && h->def_dynamic
          && !h->def_regular)
        {
          /* Make sure this symbol is output as a dynamic symbol.
@@ -9181,6 +9237,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
       enum elf_ppc64_reloc_type r_type;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
+      struct ppc_link_hash_entry *eh;
       Elf_Internal_Sym *sym;
       asection *sym_sec;
       struct _opd_sec_data *opd;
@@ -9203,24 +9260,21 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
        }
 
       /* Calls to dynamic lib functions go through a plt call stub
-        that uses r2.  Branches to undefined symbols might be a call
-        using old-style dot symbols that can be satisfied by a plt
-        call into a new-style dynamic library.  */
-      if (sym_sec == NULL)
+        that uses r2.  */
+      eh = (struct ppc_link_hash_entry *) h;
+      if (eh != NULL
+         && (eh->elf.plt.plist != NULL
+             || (eh->oh != NULL
+                 && eh->oh->elf.plt.plist != NULL)))
        {
-         struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
-         if (eh != NULL
-             && eh->oh != NULL
-             && eh->oh->elf.plt.plist != NULL)
-           {
-             ret = 1;
-             break;
-           }
-
-         /* Ignore other undefined symbols.  */
-         continue;
+         ret = 1;
+         break;
        }
 
+      if (sym_sec == NULL)
+       /* Ignore other undefined symbols.  */
+       continue;
+
       /* Assume branches to other sections not included in the link need
         stubs too, to cover -R and absolute syms.  */
       if (sym_sec->output_section == NULL)
@@ -9742,7 +9796,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                      /* Get tls info.  */
                      char *tls_mask;
 
-                     if (!get_tls_mask (&tls_mask, NULL, &local_syms,
+                     if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
                                         irela - 1, input_bfd))
                        goto error_ret_free_internal;
                      if (*tls_mask != 0)
@@ -10234,6 +10288,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       struct ppc_link_hash_entry *fdh;
       const char *sym_name;
       unsigned long r_symndx, toc_symndx;
+      bfd_vma toc_addend;
       char tls_mask, tls_gd, tls_type;
       char sym_type;
       bfd_vma relocation;
@@ -10327,28 +10382,28 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       tls_mask = 0;
       tls_gd = 0;
       toc_symndx = 0;
-      if (IS_PPC64_TLS_RELOC (r_type))
+      if (h != NULL)
+       tls_mask = h->tls_mask;
+      else if (local_got_ents != NULL)
        {
-         if (h != NULL)
-           tls_mask = h->tls_mask;
-         else if (local_got_ents != NULL)
-           {
-             char *lgot_masks;
-             lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
-             tls_mask = lgot_masks[r_symndx];
-           }
-         if (tls_mask == 0 && r_type == R_PPC64_TLS)
-           {
-             /* Check for toc tls entries.  */
-             char *toc_tls;
+         char *lgot_masks;
+         lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
+         tls_mask = lgot_masks[r_symndx];
+       }
+      if (tls_mask == 0
+         && (r_type == R_PPC64_TLS
+             || r_type == R_PPC64_TLSGD
+             || r_type == R_PPC64_TLSLD))
+       {
+         /* Check for toc tls entries.  */
+         char *toc_tls;
 
-             if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-                                rel, input_bfd))
-               return FALSE;
+         if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+                            &local_syms, rel, input_bfd))
+           return FALSE;
 
-             if (toc_tls)
-               tls_mask = *toc_tls;
-           }
+         if (toc_tls)
+           tls_mask = *toc_tls;
        }
 
       /* Check that tls relocs are used with tls syms, and non-tls
@@ -10363,7 +10418,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  || (sym_type == STT_SECTION
                      && (sec->flags & SEC_THREAD_LOCAL) != 0))))
        {
-         if (r_type == R_PPC64_TLS && tls_mask != 0)
+         if (tls_mask != 0
+             && (r_type == R_PPC64_TLS
+                 || r_type == R_PPC64_TLSGD
+                 || r_type == R_PPC64_TLSLD))
            /* R_PPC64_TLS is OK against a symbol in the TOC.  */
            ;
          else
@@ -10405,8 +10463,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            char *toc_tls;
            int retval;
 
-           retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-                                  rel, input_bfd);
+           retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+                                  &local_syms, rel, input_bfd);
            if (retval == 0)
              return FALSE;
 
@@ -10454,6 +10512,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (toc_symndx != 0)
                {
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+                 rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
                  rel--;
@@ -10507,6 +10566,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (toc_symndx != 0)
                {
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+                 rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
                  rel--;
@@ -10553,25 +10613,33 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSLD16_LO:
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
            {
-             bfd_vma insn1, insn2, insn3;
+             unsigned int insn1, insn2, insn3;
              bfd_vma offset;
 
            tls_ldgd_opt:
-             /* We know that the next reloc is on a tls_get_addr
-                call, since ppc64_elf_tls_optimize checks this.  */
-             offset = rel[1].r_offset;
-             insn1 = bfd_get_32 (output_bfd,
-                                 contents + rel->r_offset - d_offset);
-             insn3 = bfd_get_32 (output_bfd,
-                                 contents + offset + 4);
+             offset = (bfd_vma) -1;
+             /* If not using the newer R_PPC64_TLSGD/LD to mark
+                __tls_get_addr calls, we must trust that the call
+                stays with its arg setup insns, ie. that the next
+                reloc is the __tls_get_addr call associated with
+                the current reloc.  Edit both insns.  */
+             if (input_section->has_tls_get_addr_call
+                 && rel + 1 < relend
+                 && branch_reloc_hash_match (input_bfd, rel + 1,
+                                             htab->tls_get_addr,
+                                             htab->tls_get_addr_fd))
+               offset = rel[1].r_offset;
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
+                 insn1 = bfd_get_32 (output_bfd,
+                                     contents + rel->r_offset - d_offset);
                  insn1 &= (1 << 26) - (1 << 2);
                  insn1 |= 58 << 26;    /* ld */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
-                 rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
-                                               R_PPC64_NONE);
+                 if (offset != (bfd_vma) -1)
+                   rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+                                                 R_PPC64_NONE);
                  if ((tls_mask & TLS_EXPLICIT) == 0)
                    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
                              + R_PPC64_GOT_TPREL16_DS);
@@ -10601,37 +10669,139 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        rel->r_addend -= (local_syms[r_symndx].st_value
                                          + sec->output_offset
                                          + sec->output_section->vma);
-                     rel[1].r_addend = rel->r_addend;
                    }
                  else if (toc_symndx != 0)
-                   r_symndx = toc_symndx;
+                   {
+                     r_symndx = toc_symndx;
+                     rel->r_addend = toc_addend;
+                   }
                  r_type = R_PPC64_TPREL16_HA;
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-                 rel[1].r_info = ELF64_R_INFO (r_symndx,
-                                               R_PPC64_TPREL16_LO);
-                 rel[1].r_offset += d_offset;
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info = ELF64_R_INFO (r_symndx,
+                                                   R_PPC64_TPREL16_LO);
+                     rel[1].r_offset = offset + d_offset;
+                     rel[1].r_addend = rel->r_addend;
+                   }
                }
+             bfd_put_32 (output_bfd, insn1,
+                         contents + rel->r_offset - d_offset);
+             if (offset != (bfd_vma) -1)
+               {
+                 insn3 = bfd_get_32 (output_bfd,
+                                     contents + offset + 4);
+                 if (insn3 == NOP
+                     || insn3 == CROR_151515 || insn3 == CROR_313131)
+                   {
+                     rel[1].r_offset += 4;
+                     bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                     insn2 = NOP;
+                   }
+                 bfd_put_32 (output_bfd, insn2, contents + offset);
+               }
+             if ((tls_mask & tls_gd) == 0
+                 && (tls_gd == 0 || toc_symndx != 0))
+               {
+                 /* We changed the symbol.  Start over in order
+                    to get h, sym, sec etc. right.  */
+                 rel--;
+                 continue;
+               }
+           }
+         break;
+
+       case R_PPC64_TLSGD:
+         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+           {
+             unsigned int insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             if ((tls_mask & TLS_TPRELGD) != 0)
+               {
+                 /* IE */
+                 r_type = R_PPC64_NONE;
+                 insn2 = 0x7c636a14;   /* add 3,3,13 */
+               }
+             else
+               {
+                 /* LE */
+                 if (toc_symndx != 0)
+                   {
+                     r_symndx = toc_symndx;
+                     rel->r_addend = toc_addend;
+                   }
+                 r_type = R_PPC64_TPREL16_LO;
+                 rel->r_offset = offset + d_offset;
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+               }
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+                                           R_PPC64_NONE);
+             insn3 = bfd_get_32 (output_bfd,
+                                 contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
-                 insn3 = insn2;
+                 rel->r_offset += 4;
+                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
                  insn2 = NOP;
-                 rel[1].r_offset += 4;
                }
-             bfd_put_32 (output_bfd, insn1,
-                         contents + rel->r_offset - d_offset);
              bfd_put_32 (output_bfd, insn2, contents + offset);
-             bfd_put_32 (output_bfd, insn3, contents + offset + 4);
-             if (tls_gd == 0 || toc_symndx != 0)
+             if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
                {
-                 /* We changed the symbol.  Start over in order
-                    to get h, sym, sec etc. right.  */
                  rel--;
                  continue;
                }
            }
          break;
 
+       case R_PPC64_TLSLD:
+         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+           {
+             unsigned int insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             if (toc_symndx)
+               sec = local_sections[toc_symndx];
+             for (r_symndx = 0;
+                  r_symndx < symtab_hdr->sh_info;
+                  r_symndx++)
+               if (local_sections[r_symndx] == sec)
+                 break;
+             if (r_symndx >= symtab_hdr->sh_info)
+               r_symndx = 0;
+             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+             if (r_symndx != 0)
+               rel->r_addend -= (local_syms[r_symndx].st_value
+                                 + sec->output_offset
+                                 + sec->output_section->vma);
+
+             r_type = R_PPC64_TPREL16_LO;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             rel->r_offset = offset + d_offset;
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+                                           R_PPC64_NONE);
+             insn2 = 0x38630000;       /* addi 3,3,0 */
+             insn3 = bfd_get_32 (output_bfd,
+                                 contents + offset + 4);
+             if (insn3 == NOP
+                 || insn3 == CROR_151515 || insn3 == CROR_313131)
+               {
+                 rel->r_offset += 4;
+                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                 insn2 = NOP;
+               }
+             bfd_put_32 (output_bfd, insn2, contents + offset);
+             rel--;
+             continue;
+           }
+         break;
+
        case R_PPC64_DTPMOD64:
          if (rel + 1 < relend
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
@@ -10885,6 +11055,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_NONE:
        case R_PPC64_TLS:
+       case R_PPC64_TLSGD:
+       case R_PPC64_TLSLD:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
          continue;
@@ -10999,7 +11171,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
                *offp = off | 1;
                if ((info->shared || indx != 0)
-                   && (h == NULL
+                   && (offp == &ppc64_tlsld_got (input_bfd)->offset
+                       || h == NULL
                        || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                        || h->elf.root.type != bfd_link_hash_undefweak))
                  {
@@ -11250,7 +11423,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  && h != NULL
                  && h->elf.dynindx != -1
                  && !h->elf.non_got_ref
-                 && h->elf.def_dynamic
                  && !h->elf.def_regular))
            {
              Elf_Internal_Rela outrel;
@@ -11604,7 +11776,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
 /* Adjust the value of any local symbols in opd sections.  */
 
-static bfd_boolean
+static int
 ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
                              const char *name ATTRIBUTE_UNUSED,
                              Elf_Internal_Sym *elfsym,
@@ -11616,11 +11788,11 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
   bfd_vma value;
 
   if (h != NULL)
-    return TRUE;
+    return 1;
 
   opd = get_opd_info (input_sec);
   if (opd == NULL || opd->adjust == NULL)
-    return TRUE;
+    return 1;
 
   value = elfsym->st_value - input_sec->output_offset;
   if (!info->relocatable)
@@ -11628,10 +11800,10 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
 
   adjust = opd->adjust[value / 8];
   if (adjust == -1)
-    elfsym->st_value = 0;
-  else
-    elfsym->st_value += adjust;
-  return TRUE;
+    return 2;
+
+  elfsym->st_value += adjust;
+  return 1;
 }
 
 /* Finish up dynamic symbol handling.  We set the contents of various
This page took 0.041872 seconds and 4 git commands to generate.