2010-09-24 Thomas Schwinge <thomas@codesourcery.com>
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 542928d4d4254862c2c0caac443a35f4b0371a2a..2b457d6d9bfe43e6a89151c7121fa4a1c0c4d254 100644 (file)
@@ -1,6 +1,6 @@
 /* PowerPC-specific support for 32-bit ELF
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -61,6 +61,7 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
 /* For new-style .glink and .plt.  */
 #define GLINK_PLTRESOLVE 16*4
 #define GLINK_ENTRY_SIZE 4*4
+#define TLS_GET_ADDR_GLINK_SIZE 12*4
 
 /* VxWorks uses its own plt layout, filled in by the static linker.  */
 
@@ -135,17 +136,24 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
 #define ADDIS_12_12    0x3d8c0000
 #define ADDI_11_11     0x396b0000
 #define ADD_0_11_11    0x7c0b5a14
+#define ADD_3_12_2     0x7c6c1214
 #define ADD_11_0_11    0x7d605a14
 #define B              0x48000000
 #define BCL_20_31      0x429f0005
 #define BCTR           0x4e800420
+#define BEQLR          0x4d820020
+#define CMPWI_11_0     0x2c0b0000
 #define LIS_11         0x3d600000
 #define LIS_12         0x3d800000
 #define LWZU_0_12      0x840c0000
 #define LWZ_0_12       0x800c0000
+#define LWZ_11_3       0x81630000
 #define LWZ_11_11      0x816b0000
 #define LWZ_11_30      0x817e0000
+#define LWZ_12_3       0x81830000
 #define LWZ_12_12      0x818c0000
+#define MR_0_3         0x7c601b78
+#define MR_3_0         0x7c030378
 #define MFLR_0         0x7c0802a6
 #define MFLR_12                0x7d8802a6
 #define MTCTR_0                0x7c0903a6
@@ -1300,7 +1308,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_EMB_SDAI16",    /* name */
         FALSE,                 /* partial_inplace */
@@ -1317,7 +1325,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_EMB_SDA2I16",   /* name */
         FALSE,                 /* partial_inplace */
@@ -1372,7 +1380,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
@@ -1788,7 +1796,7 @@ struct ppc_elf_obj_tdata
 
 #define is_ppc_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
-   && elf_object_id (bfd) == PPC32_ELF_TDATA)
+   && elf_object_id (bfd) == PPC32_ELF_DATA)
 
 /* Override the generic function because we store some extras.  */
 
@@ -1796,7 +1804,7 @@ static bfd_boolean
 ppc_elf_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata),
-                                 PPC32_ELF_TDATA);
+                                 PPC32_ELF_DATA);
 }
 
 /* Fix bad default arch selected for a 32 bit input bfd when the
@@ -1850,7 +1858,7 @@ ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
       elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
 
       /* pr_pid */
-      elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+      elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
 
       /* pr_reg */
       offset = 72;
@@ -1986,9 +1994,6 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
                       Elf_Internal_Shdr *shdr,
                       asection *asect)
 {
-  if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE)
-    shdr->sh_flags |= SHF_EXCLUDE;
-
   if ((asect->flags & SEC_SORT_ENTRIES) != 0)
     shdr->sh_type = SHT_ORDERED;
 
@@ -2069,12 +2074,13 @@ typedef struct apuinfo_list
 apuinfo_list;
 
 static apuinfo_list *head;
-
+static bfd_boolean apuinfo_set;
 
 static void
 apuinfo_list_init (void)
 {
   head = NULL;
+  apuinfo_set = FALSE;
 }
 
 static void
@@ -2151,123 +2157,93 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
 {
   bfd *ibfd;
   asection *asec;
-  char *buffer;
-  unsigned num_input_sections;
-  bfd_size_type        output_section_size;
+  char *buffer = NULL;
+  bfd_size_type largest_input_size = 0;
   unsigned i;
-  unsigned num_entries;
-  unsigned long        offset;
   unsigned long length;
   const char *error_message = NULL;
 
   if (link_info == NULL)
     return;
 
-  /* Scan the input bfds, looking for apuinfo sections.  */
-  num_input_sections = 0;
-  output_section_size = 0;
-
-  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
-    {
-      asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
-      if (asec)
-       {
-         ++ num_input_sections;
-         output_section_size += asec->size;
-       }
-    }
-
-  /* We need at least one input sections
-     in order to make merging worthwhile.  */
-  if (num_input_sections < 1)
-    return;
-
-  /* Just make sure that the output section exists as well.  */
-  asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
-  if (asec == NULL)
-    return;
-
-  /* Allocate a buffer for the contents of the input sections.  */
-  buffer = bfd_malloc (output_section_size);
-  if (buffer == NULL)
-    return;
-
-  offset = 0;
   apuinfo_list_init ();
 
   /* Read in the input sections contents.  */
   for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
     {
       unsigned long datum;
-      char *ptr;
 
       asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
       if (asec == NULL)
        continue;
 
+      error_message = _("corrupt %s section in %B");
       length = asec->size;
-      if (length < 24)
+      if (length < 20)
+       goto fail;
+
+      apuinfo_set = TRUE;
+      if (largest_input_size < asec->size)
        {
-         error_message = _("corrupt or empty %s section in %B");
-         goto fail;
+         if (buffer)
+           free (buffer);
+         largest_input_size = asec->size;
+         buffer = bfd_malloc (largest_input_size);
+         if (!buffer)
+           return;
        }
 
       if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
-         || (bfd_bread (buffer + offset, length, ibfd) != length))
+         || (bfd_bread (buffer, length, ibfd) != length))
        {
          error_message = _("unable to read in %s section from %B");
          goto fail;
        }
 
-      /* Process the contents of the section.  */
-      ptr = buffer + offset;
-      error_message = _("corrupt %s section in %B");
-
       /* Verify the contents of the header.  Note - we have to
         extract the values this way in order to allow for a
         host whose endian-ness is different from the target.  */
-      datum = bfd_get_32 (ibfd, ptr);
+      datum = bfd_get_32 (ibfd, buffer);
       if (datum != sizeof APUINFO_LABEL)
        goto fail;
 
-      datum = bfd_get_32 (ibfd, ptr + 8);
+      datum = bfd_get_32 (ibfd, buffer + 8);
       if (datum != 0x2)
        goto fail;
 
-      if (strcmp (ptr + 12, APUINFO_LABEL) != 0)
+      if (strcmp (buffer + 12, APUINFO_LABEL) != 0)
        goto fail;
 
       /* Get the number of bytes used for apuinfo entries.  */
-      datum = bfd_get_32 (ibfd, ptr + 4);
+      datum = bfd_get_32 (ibfd, buffer + 4);
       if (datum + 20 != length)
        goto fail;
 
-      /* Make sure that we do not run off the end of the section.  */
-      if (offset + length > output_section_size)
-       goto fail;
-
       /* Scan the apuinfo section, building a list of apuinfo numbers.  */
       for (i = 0; i < datum; i += 4)
-       apuinfo_list_add (bfd_get_32 (ibfd, ptr + 20 + i));
-
-      /* Update the offset.  */
-      offset += length;
+       apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i));
     }
 
   error_message = NULL;
 
-  /* Compute the size of the output section.  */
-  num_entries = apuinfo_list_length ();
-  output_section_size = 20 + num_entries * 4;
+  if (apuinfo_set)
+    {
+      /* Compute the size of the output section.  */
+      unsigned num_entries = apuinfo_list_length ();
 
-  asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+      /* Set the output section size, if it exists.  */
+      asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
 
-  if (! bfd_set_section_size (abfd, asec, output_section_size))
-    ibfd = abfd,
-      error_message = _("warning: unable to set size of %s section in %B");
+      if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
+       {
+         ibfd = abfd;
+         error_message = _("warning: unable to set size of %s section in %B");
+       }
+    }
 
  fail:
-  free (buffer);
+  if (buffer)
+    free (buffer);
 
   if (error_message)
     (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
@@ -2282,8 +2258,7 @@ ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED,
                       asection *asec,
                       bfd_byte *contents ATTRIBUTE_UNUSED)
 {
-  return (apuinfo_list_length ()
-         && strcmp (asec->name, APUINFO_SECTION_NAME) == 0);
+  return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0;
 }
 
 /* Finally we can generate the output section.  */
@@ -2301,7 +2276,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
   if (asec == NULL)
     return;
 
-  if (apuinfo_list_length () == 0)
+  if (!apuinfo_set)
     return;
 
   length = asec->size;
@@ -2733,7 +2708,7 @@ struct ppc_elf_link_hash_table
 
   /* The bfd that forced an old-style PLT.  */
   bfd *old_bfd;
+
   /* TLS local dynamic got entry handling.  */
   union {
     bfd_signed_vma refcount;
@@ -2754,6 +2729,9 @@ struct ppc_elf_link_hash_table
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
+  /* Set if __tls_get_addr optimization should not be done.  */
+  unsigned int no_tls_get_addr_opt:1;
+
   /* True if the target system is VxWorks.  */
   unsigned int is_vxworks:1;
 
@@ -2768,10 +2746,20 @@ struct ppc_elf_link_hash_table
   struct sym_cache sym_cache;
 };
 
+/* Rename some of the generic section flags to better document how they
+   are used here.  */
+
+/* Nonzero if this section has TLS related relocations.  */
+#define has_tls_reloc sec_flg0
+
+/* Nonzero if this section has a call to __tls_get_addr.  */
+#define has_tls_get_addr_call sec_flg1
+
 /* Get the PPC ELF linker hash table from a link_info structure.  */
 
 #define ppc_elf_hash_table(p) \
-  ((struct ppc_elf_link_hash_table *) (p)->hash)
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL)
 
 /* Create an entry in a PPC ELF linker hash table.  */
 
@@ -2815,7 +2803,8 @@ ppc_elf_link_hash_table_create (bfd *abfd)
 
   if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
                                      ppc_elf_link_hash_newfunc,
-                                     sizeof (struct ppc_elf_link_hash_entry)))
+                                     sizeof (struct ppc_elf_link_hash_entry),
+                                     PPC32_ELF_DATA))
     {
       free (ret);
       return NULL;
@@ -3122,16 +3111,18 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       *valp = sym->st_size;
     }
 
-  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+  if ((abfd->flags & DYNAMIC) == 0
+      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
     elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
 
   return TRUE;
 }
 \f
 static bfd_boolean
-create_sdata_sym (struct ppc_elf_link_hash_table *htab,
-                 elf_linker_section_t *lsect)
+create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect)
 {
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
   lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
                                     TRUE, FALSE, TRUE);
   if (lsect->sym == NULL)
@@ -3139,6 +3130,7 @@ create_sdata_sym (struct ppc_elf_link_hash_table *htab,
   if (lsect->sym->root.type == bfd_link_hash_new)
     lsect->sym->non_elf = 0;
   lsect->sym->ref_regular = 1;
+  _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE);
   return TRUE;
 }
 
@@ -3168,7 +3160,7 @@ ppc_elf_create_linker_section (bfd *abfd,
     return FALSE;
   lsect->section = s;
 
-  return create_sdata_sym (htab, lsect);
+  return create_sdata_sym (info, lsect);
 }
 
 /* Find a linker generated pointer with a given addend and type.  */
@@ -3310,6 +3302,8 @@ update_plt_info (bfd *abfd, struct plt_entry **plist,
 {
   struct plt_entry *ent;
 
+  if (addend < 32768)
+    sec = NULL;
   for (ent = *plist; ent != NULL; ent = ent->next)
     if (ent->sec == sec && ent->addend == addend)
       break;
@@ -3430,7 +3424,6 @@ ppc_elf_check_relocs (bfd *abfd,
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
       int tls_type;
-      struct plt_entry **ifunc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3458,47 +3451,38 @@ ppc_elf_check_relocs (bfd *abfd,
        }
 
       tls_type = 0;
-      ifunc = NULL;
       r_type = ELF32_R_TYPE (rel->r_info);
-      if (!htab->is_vxworks)
+      if (h == NULL && !htab->is_vxworks)
        {
-         if (h != NULL)
-           {
-             if (h->type == STT_GNU_IFUNC)
-               ifunc = &h->plt.plist;
-           }
-         else
+         Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                                         abfd, r_symndx);
+         if (isym == NULL)
+           return FALSE;
+
+         if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
+             && (!info->shared
+                 || is_branch_reloc (r_type)))
            {
-             Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                                             abfd, r_symndx);
-             if (isym == NULL)
+             struct plt_entry **ifunc;
+             bfd_vma addend;
+
+             ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                            PLT_IFUNC);
+             if (ifunc == NULL)
                return FALSE;
 
-             if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
-                 && (!info->shared
-                     || is_branch_reloc (r_type)))
+             /* STT_GNU_IFUNC symbols must have a PLT entry;
+                In a non-pie executable even when there are
+                no plt calls.  */
+             addend = 0;
+             if (r_type == R_PPC_PLTREL24)
                {
-                 bfd_vma addend;
-
-                 ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
-                                                PLT_IFUNC);
-                 if (ifunc == NULL)
-                   return FALSE;
-
-                 /* STT_GNU_IFUNC symbols must have a PLT entry;
-                    In a non-pie executable even when there are
-                    no plt calls.  */
-                 addend = 0;
-                 if (r_type == R_PPC_PLTREL24)
-                   {
-                     ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                     if (info->shared)
-                       addend = rel->r_addend;
-                   }
-                 if (!update_plt_info (abfd, ifunc,
-                                       addend < 32768 ? NULL : got2, addend))
-                   return FALSE;
+                 ppc_elf_tdata (abfd)->makes_plt_call = 1;
+                 if (info->shared)
+                   addend = rel->r_addend;
                }
+             if (!update_plt_info (abfd, ifunc, got2, addend))
+               return FALSE;
            }
        }
 
@@ -3633,13 +3617,8 @@ ppc_elf_check_relocs (bfd *abfd,
          break;
 
        case R_PPC_SDAREL16:
-         if (info->shared)
-           {
-             bad_shared_reloc (abfd, r_type);
-             return FALSE;
-           }
          if (htab->sdata[0].sym == NULL
-             && !create_sdata_sym (htab, &htab->sdata[0]))
+             && !create_sdata_sym (info, &htab->sdata[0]))
            return FALSE;
          if (h != NULL)
            {
@@ -3655,7 +3634,7 @@ ppc_elf_check_relocs (bfd *abfd,
              return FALSE;
            }
          if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (htab, &htab->sdata[1]))
+             && !create_sdata_sym (info, &htab->sdata[1]))
            return FALSE;
          if (h != NULL)
            {
@@ -3672,10 +3651,10 @@ ppc_elf_check_relocs (bfd *abfd,
              return FALSE;
            }
          if (htab->sdata[0].sym == NULL
-             && !create_sdata_sym (htab, &htab->sdata[0]))
+             && !create_sdata_sym (info, &htab->sdata[0]))
            return FALSE;
          if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (htab, &htab->sdata[1]))
+             && !create_sdata_sym (info, &htab->sdata[1]))
            return FALSE;
          if (h != NULL)
            {
@@ -3740,8 +3719,7 @@ ppc_elf_check_relocs (bfd *abfd,
                    addend = rel->r_addend;
                }
              h->needs_plt = 1;
-             if (!update_plt_info (abfd, &h->plt.plist,
-                                   addend < 32768 ? NULL : got2, addend))
+             if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
                return FALSE;
            }
          break;
@@ -3772,10 +3750,9 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_EMB_MRKREF:
        case R_PPC_NONE:
        case R_PPC_max:
-       case R_PPC_RELAX32:
-       case R_PPC_RELAX32PC:
-       case R_PPC_RELAX32_PLT:
-       case R_PPC_RELAX32PC_PLT:
+       case R_PPC_RELAX:
+       case R_PPC_RELAX_PLT:
+       case R_PPC_RELAX_PLTREL24:
          break;
 
          /* These should only appear in dynamic objects.  */
@@ -3953,7 +3930,7 @@ ppc_elf_check_relocs (bfd *abfd,
                      || !h->def_regular)))
            {
              struct ppc_elf_dyn_relocs *p;
-             struct ppc_elf_dyn_relocs **head;
+             struct ppc_elf_dyn_relocs **rel_head;
 
 #ifdef DEBUG
              fprintf (stderr,
@@ -3978,7 +3955,7 @@ ppc_elf_check_relocs (bfd *abfd,
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 head = &ppc_elf_hash_entry (h)->dyn_relocs;
+                 rel_head = &ppc_elf_hash_entry (h)->dyn_relocs;
                }
              else
                {
@@ -3999,17 +3976,17 @@ ppc_elf_check_relocs (bfd *abfd,
                    s = sec;
 
                  vpp = &elf_section_data (s)->local_dynrel;
-                 head = (struct ppc_elf_dyn_relocs **) vpp;
+                 rel_head = (struct ppc_elf_dyn_relocs **) vpp;
                }
 
-             p = *head;
+             p = *rel_head;
              if (p == NULL || p->sec != sec)
                {
                  p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                  if (p == NULL)
                    return FALSE;
-                 p->next = *head;
-                 *head = p;
+                 p->next = *rel_head;
+                 *rel_head = p;
                  p->sec = sec;
                  p->count = 0;
                  p->pc_count = 0;
@@ -4067,15 +4044,15 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
          (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
       else if (out_attr->i == 1 && in_attr->i == 3)
        _bfd_error_handler
-         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), 
+         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
          obfd, ibfd);
       else if (out_attr->i == 3 && in_attr->i == 1)
        _bfd_error_handler
-         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), 
+         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
          ibfd, obfd);
       else if (out_attr->i == 3 && in_attr->i == 2)
        _bfd_error_handler
-         (_("Warning: %B uses soft float, %B uses single-precision hard float"), 
+         (_("Warning: %B uses soft float, %B uses single-precision hard float"),
          ibfd, obfd);
       else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
        _bfd_error_handler
@@ -4280,6 +4257,8 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   htab = ppc_elf_hash_table (info);
 
+  htab->emit_stub_syms = emit_stub_syms;
+
   if (htab->plt_type == PLT_UNSET)
     {
       if (plt_style == PLT_OLD)
@@ -4313,8 +4292,6 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
     info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd);
 
-  htab->emit_stub_syms = emit_stub_syms;
-
   BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
 
   if (htab->plt_type == PLT_NEW)
@@ -4478,7 +4455,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
                  struct plt_entry *ent;
 
                  ent = find_plt_ent (&h->plt.plist, NULL, 0);
-                 if (ent->plt.refcount > 0)
+                 if (ent != NULL && ent->plt.refcount > 0)
                    ent->plt.refcount -= 1;
                }
            }
@@ -4526,7 +4503,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
              if (r_type == R_PPC_PLTREL24 && info->shared)
                addend = rel->r_addend;
              ent = find_plt_ent (&h->plt.plist, got2, addend);
-             if (ent->plt.refcount > 0)
+             if (ent != NULL && ent->plt.refcount > 0)
                ent->plt.refcount -= 1;
            }
          break;
@@ -4542,11 +4519,63 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
    generic ELF tls_setup function.  */
 
 asection *
-ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+ppc_elf_tls_setup (bfd *obfd,
+                  struct bfd_link_info *info,
+                  int no_tls_get_addr_opt)
 {
   struct ppc_elf_link_hash_table *htab;
 
   htab = ppc_elf_hash_table (info);
+  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                                            FALSE, FALSE, TRUE);
+  if (!no_tls_get_addr_opt)
+    {
+      struct elf_link_hash_entry *opt, *tga;
+      opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
+                                 FALSE, FALSE, TRUE);
+      if (opt != NULL
+         && (opt->root.type == bfd_link_hash_defined
+             || opt->root.type == bfd_link_hash_defweak))
+       {
+         /* If glibc supports an optimized __tls_get_addr call stub,
+            signalled by the presence of __tls_get_addr_opt, and we'll
+            be calling __tls_get_addr via a plt call stub, then
+            make __tls_get_addr point to __tls_get_addr_opt.  */
+         tga = htab->tls_get_addr;
+         if (htab->elf.dynamic_sections_created
+             && tga != NULL
+             && (tga->type == STT_FUNC
+                 || tga->needs_plt)
+             && !(SYMBOL_CALLS_LOCAL (info, tga)
+                  || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
+                      && tga->root.type == bfd_link_hash_undefweak)))
+           {
+             struct plt_entry *ent;
+             for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
+               if (ent->plt.refcount > 0)
+                 break;
+             if (ent != NULL)
+               {
+                 tga->root.type = bfd_link_hash_indirect;
+                 tga->root.u.i.link = &opt->root;
+                 ppc_elf_copy_indirect_symbol (info, opt, tga);
+                 if (opt->dynindx != -1)
+                   {
+                     /* Use __tls_get_addr_opt in dynamic relocations.  */
+                     opt->dynindx = -1;
+                     _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                             opt->dynstr_index);
+                     if (!bfd_elf_link_record_dynamic_symbol (info, opt))
+                       return FALSE;
+                   }
+                 htab->tls_get_addr = opt;
+               }
+           }
+       }
+      else
+       no_tls_get_addr_opt = TRUE;
+    }
+  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
   if (htab->plt_type == PLT_NEW
       && htab->plt != NULL
       && htab->plt->output_section != NULL)
@@ -4555,8 +4584,6 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
       elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
     }
 
-  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
-                                            FALSE, FALSE, TRUE);
   return _bfd_elf_tls_setup (obfd, info);
 }
 
@@ -4612,6 +4639,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
       {
        Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+       asection *got2 = bfd_get_section_by_name (ibfd, ".got2");
 
        for (sec = ibfd->sections; sec != NULL; sec = sec->next)
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
@@ -4705,6 +4733,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      else
                        continue;
 
+                   case R_PPC_TLSGD:
+                   case R_PPC_TLSLD:
+                     expecting_tls_get_addr = 2;
+                     tls_set = 0;
+                     tls_clear = 0;
+                     break;
+
                    default:
                      continue;
                    }
@@ -4712,7 +4747,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                  if (pass == 0)
                    {
                      if (!expecting_tls_get_addr
-                         || !sec->has_tls_get_addr_call)
+                         || (expecting_tls_get_addr == 1
+                             && !sec->has_tls_get_addr_call))
                        continue;
 
                      if (rel + 1 < relend
@@ -4728,6 +4764,23 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      break;
                    }
 
+                 if (expecting_tls_get_addr)
+                   {
+                     struct plt_entry *ent;
+                     bfd_vma addend = 0;
+
+                     if (info->shared
+                         && 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,
+                                         got2, addend);
+                     if (ent != NULL && ent->plt.refcount > 0)
+                       ent->plt.refcount -= 1;
+
+                     if (expecting_tls_get_addr == 2)
+                       continue;
+                   }
+
                  if (h != NULL)
                    {
                      tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
@@ -4735,7 +4788,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                    }
                  else
                    {
-                     Elf_Internal_Sym *sym;
                      bfd_signed_vma *lgot_refs;
                      struct plt_entry **local_plt;
                      char *lgot_masks;
@@ -4754,7 +4806,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                              return FALSE;
                            }
                        }
-                     sym = locsyms + r_symndx;
                      lgot_refs = elf_local_got_refcounts (ibfd);
                      if (lgot_refs == NULL)
                        abort ();
@@ -4772,16 +4823,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                        *got_count -= 1;
                    }
 
-                 if (expecting_tls_get_addr)
-                   {
-                     struct plt_entry *ent;
-
-                     ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
-                                         NULL, 0);
-                     if (ent != NULL && ent->plt.refcount > 0)
-                       ent->plt.refcount -= 1;
-                   }
-
                  *tls_mask |= tls_set;
                  *tls_mask &= ~tls_clear;
                }
@@ -5147,6 +5188,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                      {
                        glink_offset = s->size;
                        s->size += GLINK_ENTRY_SIZE;
+                       if (h == htab->tls_get_addr
+                           && !htab->no_tls_get_addr_opt)
+                         s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
                      }
                    if (!doneone
                        && !info->shared
@@ -5183,7 +5227,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
                        /* If this symbol is not defined in a regular
                           file, and we are not generating a shared
-                          library, then set the symbol to this location 
+                          library, then set the symbol to this location
                           in the .plt.  This is to avoid text
                           relocations, and is required to make
                           function pointers compare as equal between
@@ -5559,6 +5603,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       local_plt = (struct plt_entry **) end_local_got;
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (char *) end_local_plt;
+
       for (; local_got < end_local_got; ++local_got, ++lgot_masks)
        if (*local_got > 0)
          {
@@ -5602,7 +5647,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          for (ent = *local_plt; ent != NULL; ent = ent->next)
            if (ent->plt.refcount > 0)
              {
-               asection *s = htab->iplt;
+               s = htab->iplt;
 
                if (!doneone)
                  {
@@ -5660,6 +5705,18 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       htab->elf.hgot->root.u.def.value = g_o_t;
     }
+  if (info->shared)
+    {
+      struct elf_link_hash_entry *sda = htab->sdata[0].sym;
+      if (sda != NULL
+         && !(sda->root.type == bfd_link_hash_defined
+              || sda->root.type == bfd_link_hash_defweak))
+       {
+         sda->root.type = bfd_link_hash_defined;
+         sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
+         sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
+       }
+    }
 
   if (htab->glink != NULL
       && htab->glink->size != 0
@@ -5811,6 +5868,11 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        {
          if (!add_dynamic_entry (DT_PPC_GOT, 0))
            return FALSE;
+         if (!htab->no_tls_get_addr_opt
+             && htab->tls_get_addr != NULL
+             && htab->tls_get_addr->plt.plist != NULL
+             && !add_dynamic_entry (DT_PPC_TLSOPT, 0))
+           return FALSE;
        }
 
       if (relocs)
@@ -5857,23 +5919,25 @@ ppc_elf_hash_symbol (struct elf_link_hash_entry *h)
 \f
 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
 
+/* Relaxation trampolines.  r12 is available for clobbering (r11, is
+   used for some functions that are allowed to break the ABI).  */
 static const int shared_stub_entry[] =
   {
     0x7c0802a6, /* mflr 0 */
     0x429f0005, /* bcl 20, 31, .Lxxx */
-    0x7d6802a6, /* mflr 11 */
-    0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */
-    0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */
+    0x7d8802a6, /* mflr 12 */
+    0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */
+    0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */
     0x7c0803a6, /* mtlr 0 */
-    0x7d6903a6, /* mtctr 11 */
+    0x7d8903a6, /* mtctr 12 */
     0x4e800420, /* bctr */
   };
 
 static const int stub_entry[] =
   {
-    0x3d600000, /* lis 11,xxx@ha */
-    0x396b0000, /* addi 11,11,xxx@l */
-    0x7d6903a6, /* mtctr 11 */
+    0x3d800000, /* lis 12,xxx@ha */
+    0x398c0000, /* addi 12,12,xxx@l */
+    0x7d8903a6, /* mtctr 12 */
     0x4e800420, /* bctr */
   };
 
@@ -5887,6 +5951,8 @@ ppc_elf_relax_section (bfd *abfd,
   {
     struct one_fixup *next;
     asection *tsec;
+    /* Final link, can use the symbol offset.  For a
+       relocatable link we use the symbol's index.  */
     bfd_vma toff;
     bfd_vma trampoff;
   };
@@ -5901,12 +5967,14 @@ ppc_elf_relax_section (bfd *abfd,
   struct ppc_elf_link_hash_table *htab;
   bfd_size_type trampoff;
   asection *got2;
+  bfd_boolean maybe_pasted;
 
   *again = FALSE;
 
   /* Nothing to do if there are no relocations, and no need to do
-     anything with non-alloc sections.  */
+     anything with non-alloc or non-code sections.  */
   if ((isec->flags & SEC_ALLOC) == 0
+      || (isec->flags & SEC_CODE) == 0
       || (isec->flags & SEC_RELOC) == 0
       || isec->reloc_count == 0)
     return TRUE;
@@ -5916,10 +5984,13 @@ ppc_elf_relax_section (bfd *abfd,
      anyway.  */
   if (link_info->relocatable && link_info->shared)
      return TRUE;
-  
+
   trampoff = (isec->size + 3) & (bfd_vma) -4;
+  maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0
+                 || strcmp (isec->output_section->name, ".fini") == 0);
   /* Space for a branch around any trampolines.  */
-  trampoff += 4;
+  if (maybe_pasted)
+    trampoff += 4;
 
   symtab_hdr = &elf_symtab_hdr (abfd);
 
@@ -5936,7 +6007,7 @@ ppc_elf_relax_section (bfd *abfd,
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       unsigned long r_type = ELF32_R_TYPE (irel->r_info);
-      bfd_vma symaddr, reladdr, toff, roff;
+      bfd_vma toff, roff;
       asection *tsec;
       struct one_fixup *f;
       size_t insn_offset = 0;
@@ -6018,7 +6089,7 @@ ppc_elf_relax_section (bfd *abfd,
                   || h->root.type == bfd_link_hash_undefweak)
            {
              tsec = bfd_und_section_ptr;
-             toff = 0;
+             toff = link_info->relocatable ? indx : 0;
            }
          else
            continue;
@@ -6119,19 +6190,22 @@ ppc_elf_relax_section (bfd *abfd,
       if (tsec->output_section == NULL)
        continue;
 
-      symaddr = tsec->output_section->vma + tsec->output_offset + toff;
-
       roff = irel->r_offset;
-      reladdr = isec->output_section->vma + isec->output_offset + roff;
 
       /* If the branch is in range, no need to do anything.  */
       if (tsec != bfd_und_section_ptr
          && (!link_info->relocatable
              /* A relocatable link may have sections moved during
                 final link, so do not presume they remain in range.  */
-             || tsec->output_section == isec->output_section)
-         && symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
-       continue;
+             || tsec->output_section == isec->output_section))
+       {
+         bfd_vma symaddr, reladdr;
+
+         symaddr = tsec->output_section->vma + tsec->output_offset + toff;
+         reladdr = isec->output_section->vma + isec->output_offset + roff;
+         if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
+           continue;
+       }
 
       /* Look for an existing fixup to this address.  */
       for (f = fixups; f ; f = f->next)
@@ -6153,28 +6227,28 @@ ppc_elf_relax_section (bfd *abfd,
            {
              size = 4 * ARRAY_SIZE (shared_stub_entry);
              insn_offset = 12;
-             stub_rtype = R_PPC_RELAX32PC;
            }
          else
            {
              size = 4 * ARRAY_SIZE (stub_entry);
              insn_offset = 0;
-             stub_rtype = R_PPC_RELAX32;
            }
-
-         if (R_PPC_RELAX32_PLT - R_PPC_RELAX32
-             != R_PPC_RELAX32PC_PLT - R_PPC_RELAX32PC)
-           abort ();
+         stub_rtype = R_PPC_RELAX;
          if (tsec == htab->plt
              || tsec == htab->glink)
-           stub_rtype += R_PPC_RELAX32_PLT - R_PPC_RELAX32;
+           {
+             stub_rtype = R_PPC_RELAX_PLT;
+             if (r_type == R_PPC_PLTREL24)
+               stub_rtype = R_PPC_RELAX_PLTREL24;
+           }
 
          /* Hijack the old relocation.  Since we need two
             relocations for this use a "composite" reloc.  */
          irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                       stub_rtype);
          irel->r_offset = trampoff + insn_offset;
-         if (r_type == R_PPC_PLTREL24)
+         if (r_type == R_PPC_PLTREL24
+             && stub_rtype != R_PPC_RELAX_PLTREL24)
            irel->r_addend = 0;
 
          /* Record the fixup so we don't do it again this section.  */
@@ -6241,7 +6315,6 @@ ppc_elf_relax_section (bfd *abfd,
     {
       const int *stub;
       bfd_byte *dest;
-      bfd_vma val;
       int i, size;
 
       do
@@ -6257,12 +6330,15 @@ ppc_elf_relax_section (bfd *abfd,
        goto error_return;
 
       isec->size = (isec->size + 3) & (bfd_vma) -4;
-      /* Branch around the trampolines.  */
-      val = B + trampoff - isec->size;
       dest = contents + isec->size;
+      /* Branch around the trampolines.  */
+      if (maybe_pasted)
+       {
+         bfd_vma val = B + trampoff - isec->size;
+         bfd_put_32 (abfd, val, dest);
+         dest += 4;
+       }
       isec->size = trampoff;
-      bfd_put_32 (abfd, val, dest);
-      dest += 4;
 
       if (link_info->shared)
        {
@@ -6318,7 +6394,7 @@ ppc_elf_relax_section (bfd *abfd,
       Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count)
                                                  * sizeof (*new_relocs));
       unsigned ix;
-      
+
       if (!new_relocs)
        goto error_return;
       memcpy (new_relocs, internal_relocs,
@@ -6344,7 +6420,7 @@ ppc_elf_relax_section (bfd *abfd,
     {
       /* Convert the internal relax relocs to external form.  */
       for (irel = internal_relocs; irel < irelend; irel++)
-       if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX32)
+       if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX)
          {
            unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
 
@@ -6360,7 +6436,7 @@ ppc_elf_relax_section (bfd *abfd,
            irel++;
          }
     }
-  
+
   return TRUE;
 
  error_return:
@@ -6437,9 +6513,10 @@ elf_finish_pointer_linker_section (bfd *input_bfd,
       linker_section_ptr->offset += 1;
     }
 
-  relocation = (lsect->section->output_offset
+  relocation = (lsect->section->output_section->vma
+               + lsect->section->output_offset
                + linker_section_ptr->offset - 1
-               - 0x8000);
+               - SYM_VAL (lsect->sym));
 
 #ifdef DEBUG
   fprintf (stderr,
@@ -6447,9 +6524,7 @@ elf_finish_pointer_linker_section (bfd *input_bfd,
           lsect->name, (long) relocation, (long) relocation);
 #endif
 
-  /* Subtract out the addend, because it will get added back in by the normal
-     processing.  */
-  return relocation - linker_section_ptr->addend;
+  return relocation;
 }
 
 #define PPC_LO(v) ((v) & 0xffff)
@@ -6457,18 +6532,16 @@ elf_finish_pointer_linker_section (bfd *input_bfd,
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 static void
-write_glink_stub (struct plt_entry *ent, asection *plt_sec,
+write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
                  struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
   bfd *output_bfd = info->output_bfd;
   bfd_vma plt;
-  unsigned char *p;
 
   plt = ((ent->plt.offset & ~1)
         + plt_sec->output_section->vma
         + plt_sec->output_offset);
-  p = (unsigned char *) htab->glink->contents + ent->glink_offset;
 
   if (info->shared)
     {
@@ -6519,6 +6592,102 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec,
     }
 }
 
+/* Return true if symbol is defined statically.  */
+
+static bfd_boolean
+is_static_defined (struct elf_link_hash_entry *h)
+{
+  return ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section != NULL
+         && h->root.u.def.section->output_section != NULL);
+}
+
+/* If INSN is an opcode that may be used with an @tls operand, return
+   the transformed insn for TLS optimisation, otherwise return 0.  If
+   REG is non-zero only match an insn with RB or RA equal to REG.  */
+
+unsigned int
+_bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
+{
+  unsigned int rtra;
+
+  if ((insn & (0x3f << 26)) != 31 << 26)
+    return 0;
+
+  if (reg == 0 || ((insn >> 11) & 0x1f) == reg)
+    rtra = insn & ((1 << 26) - (1 << 16));
+  else if (((insn >> 16) & 0x1f) == reg)
+    rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5);
+  else
+    return 0;
+
+  if ((insn & (0x3ff << 1)) == 266 << 1)
+    /* add -> addi.  */
+    insn = 14 << 26;
+  else if ((insn & (0x1f << 1)) == 23 << 1
+          && ((insn & (0x1f << 6)) < 14 << 6
+              || ((insn & (0x1f << 6)) >= 16 << 6
+                  && (insn & (0x1f << 6)) < 24 << 6)))
+    /* load and store indexed -> dform.  */
+    insn = (32 | ((insn >> 6) & 0x1f)) << 26;
+  else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1)
+    /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
+    insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1);
+  else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1)
+    /* lwax -> lwa.  */
+    insn = (58 << 26) | 2;
+  else
+    return 0;
+  insn |= rtra;
+  return insn;
+}
+
+/* If INSN is an opcode that may be used with an @tprel operand, return
+   the transformed insn for an undefined weak symbol, ie. with the
+   thread pointer REG operand removed.  Otherwise return 0.  */
+
+unsigned int
+_bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg)
+{
+  if ((insn & (0x1f << 16)) == reg << 16
+      && ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+         || (insn & (0x3f << 26)) == 15u << 26 /* addis */
+         || (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))))
+    {
+      insn &= ~(0x1f << 16);
+    }
+  else if ((insn & (0x1f << 21)) == reg << 21
+          && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */
+              || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */
+              || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */))
+    {
+      insn &= ~(0x1f << 21);
+      insn |= (insn & (0x1f << 16)) << 5;
+      if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */)
+       insn -= 2 >> 26;  /* convert to ori,oris */
+    }
+  else
+    insn = 0;
+  return insn;
+}
+
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
 
@@ -6564,7 +6733,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
   Elf_Internal_Rela outrel;
-  bfd_byte *loc;
   asection *got2, *sreloc = NULL;
   bfd_vma *local_got_offsets;
   bfd_boolean ret = TRUE;
@@ -6608,7 +6776,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
       reloc_howto_type *howto;
       unsigned long r_symndx;
       bfd_vma relocation;
-      bfd_vma branch_bit, insn, from;
+      bfd_vma branch_bit, from;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
       unsigned int tls_type, tls_mask, tls_gd;
@@ -6706,6 +6874,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              && (tls_mask & TLS_TPREL) == 0)
            {
              bfd_vma insn;
+
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
              insn &= 31 << 21;
              insn |= 0x3c020000;       /* addis 0,2,0 */
@@ -6719,37 +6888,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             bfd_vma insn, rtra;
+             bfd_vma insn;
+
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
-             if ((insn & ((31 << 26) | (31 << 11)))
-                 == ((31 << 26) | (2 << 11)))
-               rtra = insn & ((1 << 26) - (1 << 16));
-             else if ((insn & ((31 << 26) | (31 << 16)))
-                      == ((31 << 26) | (2 << 16)))
-               rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5);
-             else
+             insn = _bfd_elf_ppc_at_tls_transform (insn, 2);
+             if (insn == 0)
                abort ();
-             if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1)
-               /* add -> addi.  */
-               insn = 14 << 26;
-             else if ((insn & (31 << 1)) == 23 << 1
-                      && ((insn & (31 << 6)) < 14 << 6
-                          || ((insn & (31 << 6)) >= 16 << 6
-                              && (insn & (31 << 6)) < 24 << 6)))
-               /* load and store indexed -> dform.  */
-               insn = (32 | ((insn >> 6) & 31)) << 26;
-             else if ((insn & (31 << 1)) == 21 << 1
-                      && (insn & (0x1a << 6)) == 0)
-               /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
-               insn = (((58 | ((insn >> 6) & 4)) << 26)
-                       | ((insn >> 6) & 1));
-             else if ((insn & (31 << 1)) == 21 << 1
-                      && (insn & ((1 << 11) - (1 << 1))) == 341 << 1)
-               /* lwax -> lwa.  */
-               insn = (58 << 26) | 2;
-             else
-               abort ();
-             insn |= rtra;
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              r_type = R_PPC_TPREL16_LO;
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -6820,9 +6964,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  insn1 |= 32 << 26;    /* lwz */
                  if (offset != (bfd_vma) -1)
                    {
-                     rel[1].r_info
-                       = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
-                                       R_PPC_NONE);
+                     rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
                      insn2 = 0x7c631214;       /* add 3,3,2 */
                      bfd_put_32 (output_bfd, insn2, contents + offset);
                    }
@@ -6843,9 +6985,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                        if (local_sections[r_symndx] == sec)
                          break;
                      if (r_symndx >= symtab_hdr->sh_info)
-                       r_symndx = 0;
+                       r_symndx = STN_UNDEF;
                      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-                     if (r_symndx != 0)
+                     if (r_symndx != STN_UNDEF)
                        rel->r_addend -= (local_syms[r_symndx].st_value
                                          + sec->output_offset
                                          + sec->output_section->vma);
@@ -6896,8 +7038,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              bfd_put_32 (output_bfd, insn2, contents + offset);
              /* Zap the reloc on the _tls_get_addr call too.  */
              BFD_ASSERT (offset == rel[1].r_offset);
-             rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
-                                           R_PPC_NONE);
+             rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
            }
          break;
 
@@ -6912,9 +7053,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                if (local_sections[r_symndx] == sec)
                  break;
              if (r_symndx >= symtab_hdr->sh_info)
-               r_symndx = 0;
+               r_symndx = STN_UNDEF;
              rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-             if (r_symndx != 0)
+             if (r_symndx != STN_UNDEF)
                rel->r_addend -= (local_syms[r_symndx].st_value
                                  + sec->output_offset
                                  + sec->output_section->vma);
@@ -6926,8 +7067,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          contents + rel->r_offset - d_offset);
              /* Zap the reloc on the _tls_get_addr call too.  */
              BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
-             rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
-                                           R_PPC_NONE);
+             rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
              rel--;
              continue;
            }
@@ -6950,20 +7090,24 @@ ppc_elf_relocate_section (bfd *output_bfd,
          /* Branch not taken prediction relocations.  */
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_REL14_BRNTAKEN:
-         insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
-         insn &= ~BRANCH_PREDICT_BIT;
-         insn |= branch_bit;
+         {
+           bfd_vma insn;
 
-         from = (rel->r_offset
-                 + input_section->output_offset
-                 + input_section->output_section->vma);
+           insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+           insn &= ~BRANCH_PREDICT_BIT;
+           insn |= branch_bit;
 
-         /* Invert 'y' bit if not the default.  */
-         if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
-           insn ^= BRANCH_PREDICT_BIT;
+           from = (rel->r_offset
+                   + input_section->output_offset
+                   + input_section->output_section->vma);
 
-         bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
-         break;
+           /* Invert 'y' bit if not the default.  */
+           if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
+             insn ^= BRANCH_PREDICT_BIT;
+
+           bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+           break;
+         }
        }
 
       ifunc = NULL;
@@ -7017,7 +7161,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                }
              if (h == NULL && (ent->glink_offset & 1) == 0)
                {
-                 write_glink_stub (ent, htab->iplt, info);
+                 unsigned char *p = ((unsigned char *) htab->glink->contents
+                                     + ent->glink_offset);
+                 write_glink_stub (ent, htab->iplt, p, info);
                  ent->glink_offset |= 1;
                }
 
@@ -7192,6 +7338,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                            || h->root.type != bfd_link_hash_undefweak))
                      {
                        asection *rsec = htab->relgot;
+                       bfd_byte * loc;
 
                        outrel.r_offset = (htab->got->output_section->vma
                                           + htab->got->output_offset
@@ -7343,6 +7490,21 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
+         if (h != NULL
+             && h->root.type == bfd_link_hash_undefweak
+             && h->dynindx == -1)
+           {
+             /* Make this relocation against an undefined weak symbol
+                resolve to zero.  This is really just a tweak, since
+                code using weak externs ought to check that they are
+                defined before using them.  */
+             bfd_byte *p = contents + rel->r_offset - d_offset;
+             unsigned int insn = bfd_get_32 (output_bfd, p);
+             insn = _bfd_elf_ppc_at_tprel_transform (insn, 2);
+             if (insn != 0)
+               bfd_put_32 (output_bfd, insn, p);
+             break;
+           }
          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
@@ -7423,7 +7585,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  && !h->def_regular))
            {
              int skip;
-
+             bfd_byte * loc;
 #ifdef DEBUG
              fprintf (stderr, "ppc_elf_relocate_section needs to "
                       "create relocation for %s\n",
@@ -7444,9 +7606,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                }
 
              skip = 0;
-             outrel.r_offset =
-               _bfd_elf_section_offset (output_bfd, info, input_section,
-                                        rel->r_offset);
+             outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
+                                                        input_section,
+                                                        rel->r_offset);
              if (outrel.r_offset == (bfd_vma) -1
                  || outrel.r_offset == (bfd_vma) -2)
                skip = (int) outrel.r_offset;
@@ -7496,7 +7658,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                             sym_name);
                          ret = FALSE;
                        }
-                     else if (r_symndx == 0 || bfd_is_abs_section (sec))
+                     else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
@@ -7557,12 +7719,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
-       case R_PPC_RELAX32PC_PLT:
-       case R_PPC_RELAX32_PLT:
+       case R_PPC_RELAX_PLT:
+       case R_PPC_RELAX_PLTREL24:
          if (h != NULL)
            {
-             struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   info->shared ? addend : 0);
+             struct plt_entry *ent;
+             bfd_vma got2_addend = 0;
+
+             if (r_type == R_PPC_RELAX_PLTREL24)
+               {
+                 if (info->shared)
+                   got2_addend = addend;
+                 addend = 0;
+               }
+             ent = find_plt_ent (&h->plt.plist, got2, got2_addend);
              if (htab->plt_type == PLT_NEW)
                relocation = (htab->glink->output_section->vma
                              + htab->glink->output_offset
@@ -7572,18 +7742,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              + htab->plt->output_offset
                              + ent->plt.offset);
            }
-         if (r_type == R_PPC_RELAX32_PLT)
-           goto relax32;
          /* Fall thru */
 
-       case R_PPC_RELAX32PC:
-         relocation -= (input_section->output_section->vma
-                        + input_section->output_offset
-                        + rel->r_offset - 4);
-         /* Fall thru */
+       case R_PPC_RELAX:
+         if (info->shared)
+           relocation -= (input_section->output_section->vma
+                          + input_section->output_offset
+                          + rel->r_offset - 4);
 
-       case R_PPC_RELAX32:
-       relax32:
          {
            unsigned long t0;
            unsigned long t1;
@@ -7620,17 +7786,29 @@ ppc_elf_relocate_section (bfd *output_bfd,
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
          BFD_ASSERT (htab->sdata[0].section != NULL);
+         if (!is_static_defined (htab->sdata[0].sym))
+           {
+             unresolved_reloc = TRUE;
+             break;
+           }
          relocation
            = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0],
                                                 h, relocation, rel);
+         addend = 0;
          break;
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
          BFD_ASSERT (htab->sdata[1].section != NULL);
+         if (!is_static_defined (htab->sdata[1].sym))
+           {
+             unresolved_reloc = TRUE;
+             break;
+           }
          relocation
            = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1],
                                                 h, relocation, rel);
+         addend = 0;
          break;
 
          /* Handle the TOC16 reloc.  We want to use the offset within the .got
@@ -7683,12 +7861,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_SDAREL16:
          {
            const char *name;
+           struct elf_link_hash_entry *sda = htab->sdata[0].sym;
 
-           if (sec == NULL || sec->output_section == NULL)
+           if (sec == NULL
+               || sec->output_section == NULL
+               || !is_static_defined (sda))
              {
                unresolved_reloc = TRUE;
                break;
              }
+           addend -= SYM_VAL (sda);
 
            name = bfd_get_section_name (abfd, sec->output_section);
            if (! ((CONST_STRNEQ (name, ".sdata")
@@ -7704,7 +7886,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                   howto->name,
                   name);
              }
-           addend -= SYM_VAL (htab->sdata[0].sym);
          }
          break;
 
@@ -7712,12 +7893,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_EMB_SDA2REL:
          {
            const char *name;
+           struct elf_link_hash_entry *sda = htab->sdata[1].sym;
 
-           if (sec == NULL || sec->output_section == NULL)
+           if (sec == NULL
+               || sec->output_section == NULL
+               || !is_static_defined (sda))
              {
                unresolved_reloc = TRUE;
                break;
              }
+           addend -= SYM_VAL (sda);
 
            name = bfd_get_section_name (abfd, sec->output_section);
            if (! (CONST_STRNEQ (name, ".sdata2")
@@ -7730,12 +7915,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                   sym_name,
                   howto->name,
                   name);
-
-               bfd_set_error (bfd_error_bad_value);
-               ret = FALSE;
-               continue;
              }
-           addend -= SYM_VAL (htab->sdata[1].sym);
          }
          break;
 
@@ -7745,6 +7925,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          {
            const char *name;
            int reg;
+           struct elf_link_hash_entry *sda = NULL;
 
            if (sec == NULL || sec->output_section == NULL)
              {
@@ -7759,13 +7940,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
                     && (name[5] == 0 || name[5] == '.'))))
              {
                reg = 13;
-               addend -= SYM_VAL (htab->sdata[0].sym);
+               sda = htab->sdata[0].sym;
              }
            else if (CONST_STRNEQ (name, ".sdata2")
                     || CONST_STRNEQ (name, ".sbss2"))
              {
                reg = 2;
-               addend -= SYM_VAL (htab->sdata[1].sym);
+               sda = htab->sdata[1].sym;
              }
            else if (strcmp (name, ".PPC.EMB.sdata0") == 0
                     || strcmp (name, ".PPC.EMB.sbss0") == 0)
@@ -7787,8 +7968,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
                continue;
              }
 
+           if (sda != NULL)
+             {
+               if (!is_static_defined (sda))
+                 {
+                   unresolved_reloc = TRUE;
+                   break;
+                 }
+               addend -= SYM_VAL (sda);
+             }
+
            if (r_type == R_PPC_EMB_SDA21)
-             {                 /* fill in register field */
+             {
+               bfd_vma insn;  /* Fill in register field.  */
+
                insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
                insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
                bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
@@ -8010,7 +8203,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
              {
                bfd_vma got_offset;
                const bfd_vma *plt_entry;
-               
+
                /* The first three entries in .got.plt are reserved.  */
                got_offset = (reloc_index + 3) * 4;
 
@@ -8051,7 +8244,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   low-order 16 bits of the load instruction.  */
                /* NOTE: It appears that this is now an index rather than a
                   prescaled offset.  */
-               bfd_put_32 (output_bfd, 
+               bfd_put_32 (output_bfd,
                            plt_entry[4] | reloc_index,
                            htab->plt->contents + ent->plt.offset + 16);
                /* This instruction is a PC-relative branch whose target is
@@ -8060,8 +8253,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   The address is encoded in bits 6-29, inclusive.  The value
                   stored is right-shifted by two bits, permitting a 26-bit
                   offset.  */
-               bfd_put_32 (output_bfd, 
-                           (plt_entry[5] 
+               bfd_put_32 (output_bfd,
+                           (plt_entry[5]
                             | (-(ent->plt.offset + 20) & 0x03fffffc)),
                            htab->plt->contents + ent->plt.offset + 20);
                bfd_put_32 (output_bfd, plt_entry[6],
@@ -8210,8 +8403,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   relocation.  */
                sym->st_shndx = (_bfd_elf_section_from_bfd_section
                                 (output_bfd, htab->glink->output_section));
-               sym->st_value = (ent->glink_offset +
-                                htab->glink->output_offset
+               sym->st_value = (ent->glink_offset
+                                htab->glink->output_offset
                                 + htab->glink->output_section->vma);
              }
            doneone = TRUE;
@@ -8221,12 +8414,35 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            || !htab->elf.dynamic_sections_created
            || h->dynindx == -1)
          {
+           unsigned char *p;
            asection *splt = htab->plt;
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
              splt = htab->iplt;
 
-           write_glink_stub (ent, splt, info);
+           p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+
+           if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt)
+             {
+               bfd_put_32 (output_bfd, LWZ_11_3, p);
+               p += 4;
+               bfd_put_32 (output_bfd, LWZ_12_3 + 4, p);
+               p += 4;
+               bfd_put_32 (output_bfd, MR_0_3, p);
+               p += 4;
+               bfd_put_32 (output_bfd, CMPWI_11_0, p);
+               p += 4;
+               bfd_put_32 (output_bfd, ADD_3_12_2, p);
+               p += 4;
+               bfd_put_32 (output_bfd, BEQLR, p);
+               p += 4;
+               bfd_put_32 (output_bfd, MR_3_0, p);
+               p += 4;
+               bfd_put_32 (output_bfd, NOP, p);
+               p += 4;
+             }
+
+           write_glink_stub (ent, splt, p, info);
 
            if (!info->shared)
              /* We only need one non-PIC glink stub.  */
@@ -8317,7 +8533,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   dynobj = elf_hash_table (info)->dynobj;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
   if (htab->is_vxworks)
-    splt = bfd_get_section_by_name (dynobj, ".plt");  
+    splt = bfd_get_section_by_name (dynobj, ".plt");
   else
     splt = NULL;
 
@@ -8426,9 +8642,9 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   if (splt && splt->size > 0)
     {
       /* Use the right PLT. */
-      static const bfd_vma *plt_entry = NULL;
-      plt_entry = info->shared ? 
-       ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry;
+      const bfd_vma *plt_entry = (info->shared
+                                 ? ppc_elf_vxworks_pic_plt0_entry
+                                 : ppc_elf_vxworks_plt0_entry);
 
       if (!info->shared)
        {
@@ -8466,7 +8682,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
          rela.r_addend = 0;
          bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
          loc += sizeof (Elf32_External_Rela);
-         
+
          /* Output the @l relocation for the second instruction.  */
          rela.r_offset = (htab->plt->output_section->vma
                           + htab->plt->output_offset
@@ -8711,6 +8927,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define TARGET_BIG_SYM         bfd_elf32_powerpc_vec
 #define TARGET_BIG_NAME                "elf32-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
+#define ELF_TARGET_ID          PPC32_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC
 #ifdef __QNXTARGET__
 #define ELF_MAXPAGESIZE                0x1000
This page took 0.048953 seconds and 4 git commands to generate.