gas/
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 727b6ac2b19895d5d692d406b75bc4d72f6ad759..703a2b34cbabd160b615d421954b7825f05b0457 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
@@ -2608,9 +2608,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;
@@ -3005,8 +3011,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;
@@ -3061,21 +3067,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);
@@ -3620,7 +3626,7 @@ 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.  */
@@ -4438,7 +4444,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;
@@ -4578,6 +4584,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;
@@ -4594,6 +4601,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);
@@ -4829,25 +4840,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;
 
@@ -4891,23 +4885,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:
@@ -5028,43 +5029,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
@@ -5847,7 +5816,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))
     {
@@ -5880,7 +5849,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
@@ -6258,9 +6227,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;
@@ -6288,12 +6260,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)
@@ -6898,36 +6872,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
@@ -7173,55 +7160,26 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      if (!expecting_tls_get_addr)
                        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)
@@ -7891,7 +7849,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;
@@ -7925,7 +7884,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
@@ -7982,7 +7942,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.
@@ -9184,6 +9143,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;
@@ -9206,24 +9166,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)
@@ -9745,7 +9702,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)
@@ -10237,6 +10194,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;
@@ -10345,8 +10303,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              /* Check for toc tls entries.  */
              char *toc_tls;
 
-             if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-                                rel, input_bfd))
+             if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+                                &local_syms, rel, input_bfd))
                return FALSE;
 
              if (toc_tls)
@@ -10408,8 +10366,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;
 
@@ -10457,6 +10415,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--;
@@ -10510,6 +10469,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--;
@@ -10556,20 +10516,18 @@ 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);
              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 */
@@ -10604,28 +10562,33 @@ 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;
+                 rel[1].r_addend = rel->r_addend;
                }
+             bfd_put_32 (output_bfd, insn1,
+                         contents + rel->r_offset - d_offset);
+             insn3 = bfd_get_32 (output_bfd,
+                                 contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
-                 insn3 = insn2;
-                 insn2 = NOP;
                  rel[1].r_offset += 4;
+                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                 insn2 = NOP;
                }
-             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_gd) == 0
+                 && (tls_gd == 0 || toc_symndx != 0))
                {
                  /* We changed the symbol.  Start over in order
                     to get h, sym, sec etc. right.  */
@@ -11002,7 +10965,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))
                  {
@@ -11253,7 +11217,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;
This page took 0.035506 seconds and 4 git commands to generate.