* c-lang.c (evaluate_subexp_c): Call check_typedef.
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 84e72b8a041e1b141a1baba07cf457ae63e62767..5db64b0fa651d8b33822237eb454932f5bad007b 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 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -157,6 +157,12 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
 /* Offset of tp and dtp pointers from start of TLS block.  */
 #define TP_OFFSET      0x7000
 #define DTP_OFFSET     0x8000
+
+/* The value of a defined global symbol.  */
+#define SYM_VAL(SYM) \
+  ((SYM)->root.u.def.section->output_section->vma      \
+   + (SYM)->root.u.def.section->output_offset          \
+   + (SYM)->root.u.def.value)
 \f
 static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
 
@@ -747,7 +753,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC_TLS,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -762,6 +768,34 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC_TLSGD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_TLSGD",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC_TLSLD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_TLSLD",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC_DTPMOD32,
@@ -1525,6 +1559,8 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_CTOR:               r = R_PPC_ADDR32;               break;
     case BFD_RELOC_PPC_TOC16:          r = R_PPC_TOC16;                break;
     case BFD_RELOC_PPC_TLS:            r = R_PPC_TLS;                  break;
+    case BFD_RELOC_PPC_TLSGD:          r = R_PPC_TLSGD;                break;
+    case BFD_RELOC_PPC_TLSLD:          r = R_PPC_TLSLD;                break;
     case BFD_RELOC_PPC_DTPMOD:         r = R_PPC_DTPMOD32;             break;
     case BFD_RELOC_PPC_TPREL16:                r = R_PPC_TPREL16;              break;
     case BFD_RELOC_PPC_TPREL16_LO:     r = R_PPC_TPREL16_LO;           break;
@@ -3282,6 +3318,7 @@ ppc_elf_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *got2, *sreloc;
+  struct elf_link_hash_entry *tga;
 
   if (info->relocatable)
     return TRUE;
@@ -3307,6 +3344,8 @@ ppc_elf_check_relocs (bfd *abfd,
     ppc_elf_howto_init ();
 
   htab = ppc_elf_hash_table (info);
+  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                             FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   got2 = bfd_get_section_by_name (abfd, ".got2");
@@ -3318,7 +3357,7 @@ ppc_elf_check_relocs (bfd *abfd,
       unsigned long r_symndx;
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
-      int tls_type = 0;
+      int tls_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3345,9 +3384,44 @@ ppc_elf_check_relocs (bfd *abfd,
          BFD_ASSERT (h == htab->elf.hgot);
        }
 
+      tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      if (h != NULL && h == tga)
+       switch (r_type)
+         {
+         default:
+           break;
+
+         case R_PPC_PLTREL24:
+         case R_PPC_LOCAL24PC:
+         case R_PPC_REL24:
+         case R_PPC_REL14:
+         case R_PPC_REL14_BRTAKEN:
+         case R_PPC_REL14_BRNTAKEN:
+         case R_PPC_ADDR24:
+         case R_PPC_ADDR14:
+         case R_PPC_ADDR14_BRTAKEN:
+         case R_PPC_ADDR14_BRNTAKEN:
+           if (rel != relocs
+               && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
+                   || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
+             /* We have a new-style __tls_get_addr call with a marker
+                reloc.  */
+             ;
+           else
+             /* Mark this section as having an old-style call.  */
+             sec->has_tls_get_addr_call = 1;
+           break;
+         }
+
       switch (r_type)
        {
+       case R_PPC_TLSGD:
+       case R_PPC_TLSLD:
+         /* These special tls relocs tie a call to __tls_get_addr with
+            its parameter symbol.  */
+         break;
+
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_HI:
@@ -3601,7 +3675,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* This refers only to functions defined in the shared library.  */
        case R_PPC_LOCAL24PC:
-         if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
+         if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
            {
              htab->plt_type = PLT_OLD;
              htab->old_bfd = abfd;
@@ -3762,38 +3836,14 @@ ppc_elf_check_relocs (bfd *abfd,
 #endif
              if (sreloc == NULL)
                {
-                 const char *name;
-
-                 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;
-
-                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                             && strcmp (bfd_get_section_name (abfd, sec),
-                                        name + 5) == 0);
-
                  if (htab->elf.dynobj == NULL)
                    htab->elf.dynobj = abfd;
-                 sreloc = bfd_get_section_by_name (htab->elf.dynobj, name);
+
+                 sreloc = _bfd_elf_make_dynamic_reloc_section
+                   (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
+
                  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 (htab->elf.dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (htab->elf.dynobj,
-                                                         sreloc, 2))
-                       return FALSE;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
+                   return FALSE;
                }
 
              /* If this is a global symbol, we count the number of
@@ -3958,6 +4008,33 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
           ibfd, obfd, in_abi, out_abi);
     }
 
+  /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
+     and merge non-conflicting ones.  */
+  in_attr = &in_attrs[Tag_GNU_Power_ABI_Struct_Return];
+  out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
+  if (in_attr->i != out_attr->i)
+    {
+      out_attr->type = 1;
+      if (out_attr->i == 0)
+       out_attr->i = in_attr->i;
+      else if (in_attr->i == 0)
+       ;
+      else if (out_attr->i == 1 && in_attr->i == 2)
+       _bfd_error_handler
+         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
+      else if (out_attr->i == 2 && in_attr->i == 1)
+       _bfd_error_handler
+         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
+      else if (in_attr->i > 2)
+       _bfd_error_handler
+         (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
+          in_attr->i);
+      else
+       _bfd_error_handler
+         (_("Warning: %B uses unknown small structure return convention %d"), obfd,
+          out_attr->i);
+    }
+
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
   _bfd_elf_merge_object_attributes (ibfd, obfd);
 
@@ -4292,7 +4369,8 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
   return TRUE;
 }
 \f
-/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
+/* Set plt output section type, htab->tls_get_addr, and call the
+   generic ELF tls_setup function.  */
 
 asection *
 ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
@@ -4313,6 +4391,43 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
   return _bfd_elf_tls_setup (obfd, info);
 }
 
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+   HASH.  */
+
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+                        const Elf_Internal_Rela *rel,
+                        const struct elf_link_hash_entry *hash)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+  enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
+  unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
+
+  if (r_symndx >= symtab_hdr->sh_info
+      && (r_type == R_PPC_PLTREL24
+         || r_type == R_PPC_LOCAL24PC
+         || r_type == R_PPC_REL14
+         || r_type == R_PPC_REL14_BRTAKEN
+         || r_type == R_PPC_REL14_BRNTAKEN
+         || r_type == R_PPC_REL24
+         || r_type == R_PPC_ADDR24
+         || r_type == R_PPC_ADDR14
+         || r_type == R_PPC_ADDR14_BRTAKEN
+         || r_type == R_PPC_ADDR14_BRNTAKEN))
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *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 == hash)
+       return TRUE;
+    }
+  return FALSE;
+}
+
 /* Run through all the TLS relocs looking for optimization
    opportunities.  */
 
@@ -4437,38 +4552,14 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
 
                  if (pass == 0)
                    {
-                     if (!expecting_tls_get_addr)
+                     if (!expecting_tls_get_addr
+                         || !sec->has_tls_get_addr_call)
                        continue;
 
-                     if (rel + 1 < relend)
-                       {
-                         enum elf_ppc_reloc_type r_type2;
-                         unsigned long r_symndx2;
-                         struct elf_link_hash_entry *h2;
-
-                         /* The next instruction should be a call to
-                            __tls_get_addr.  Peek at the reloc to be sure.  */
-                         r_type2 = ELF32_R_TYPE (rel[1].r_info);
-                         r_symndx2 = ELF32_R_SYM (rel[1].r_info);
-                         if (r_symndx2 >= symtab_hdr->sh_info
-                             && (r_type2 == R_PPC_REL14
-                                 || r_type2 == R_PPC_REL14_BRTAKEN
-                                 || r_type2 == R_PPC_REL14_BRNTAKEN
-                                 || r_type2 == R_PPC_REL24
-                                 || r_type2 == R_PPC_PLTREL24))
-                           {
-                             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 == htab->tls_get_addr)
-                               continue;
-                           }
-                       }
+                     if (rel + 1 < relend
+                         && branch_reloc_hash_match (ibfd, rel + 1,
+                                                     htab->tls_get_addr))
+                       continue;
 
                      /* Uh oh, we didn't find the expected call.  We
                         could just mark this symbol to exclude it
@@ -4991,6 +5082,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   eh = (struct ppc_elf_link_hash_entry *) h;
   if (eh->elf.got.refcount > 0)
     {
+      bfd_boolean dyn;
+      unsigned int need;
+
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (eh->elf.dynindx == -1
          && !eh->elf.forced_local
@@ -5000,30 +5094,32 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            return FALSE;
        }
 
-      if (eh->tls_mask == (TLS_TLS | TLS_LD)
-         && !eh->elf.def_dynamic)
-       {
-         /* If just an LD reloc, we'll just use htab->tlsld_got.offset.  */
-         htab->tlsld_got.refcount += 1;
-         eh->elf.got.offset = (bfd_vma) -1;
-       }
-      else
+      need = 0;
+      if ((eh->tls_mask & TLS_TLS) != 0)
        {
-         bfd_boolean dyn;
-         unsigned int need = 0;
-         if ((eh->tls_mask & TLS_TLS) != 0)
+         if ((eh->tls_mask & TLS_LD) != 0)
            {
-             if ((eh->tls_mask & TLS_LD) != 0)
-               need += 8;
-             if ((eh->tls_mask & TLS_GD) != 0)
+             if (!eh->elf.def_dynamic)
+               /* We'll just use htab->tlsld_got.offset.  This should
+                  always be the case.  It's a little odd if we have
+                  a local dynamic reloc against a non-local symbol.  */
+               htab->tlsld_got.refcount += 1;
+             else
                need += 8;
-             if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
-               need += 4;
-             if ((eh->tls_mask & TLS_DTPREL) != 0)
-               need += 4;
            }
-         else
+         if ((eh->tls_mask & TLS_GD) != 0)
+           need += 8;
+         if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
            need += 4;
+         if ((eh->tls_mask & TLS_DTPREL) != 0)
+           need += 4;
+       }
+      else
+       need += 4;
+      if (need == 0)
+       eh->elf.got.offset = (bfd_vma) -1;
+      else
+       {
          eh->elf.got.offset = allocate_got (htab, need);
          dyn = htab->elf.dynamic_sections_created;
          if ((info->shared
@@ -5033,7 +5129,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            {
              /* All the entries we allocated need relocs.
                 Except LD only needs one.  */
-             if ((eh->tls_mask & TLS_LD) != 0)
+             if ((eh->tls_mask & TLS_LD) != 0
+                 && eh->elf.def_dynamic)
                need -= 4;
              htab->relgot->size += need * (sizeof (Elf32_External_Rela) / 4);
            }
@@ -5269,27 +5366,24 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       for (; local_got < end_local_got; ++local_got, ++lgot_masks)
        if (*local_got > 0)
          {
-           if (*lgot_masks == (TLS_TLS | TLS_LD))
+           unsigned int need = 0;
+           if ((*lgot_masks & TLS_TLS) != 0)
              {
-               /* If just an LD reloc, we'll just use
-                  htab->tlsld_got.offset.  */
-               htab->tlsld_got.refcount += 1;
-               *local_got = (bfd_vma) -1;
+               if ((*lgot_masks & TLS_GD) != 0)
+                 need += 8;
+               if ((*lgot_masks & TLS_LD) != 0)
+                 htab->tlsld_got.refcount += 1;
+               if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
+                 need += 4;
+               if ((*lgot_masks & TLS_DTPREL) != 0)
+                 need += 4;
              }
+           else
+             need += 4;
+           if (need == 0)
+             *local_got = (bfd_vma) -1;
            else
              {
-               unsigned int need = 0;
-               if ((*lgot_masks & TLS_TLS) != 0)
-                 {
-                   if ((*lgot_masks & TLS_GD) != 0)
-                     need += 8;
-                   if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
-                     need += 4;
-                   if ((*lgot_masks & TLS_DTPREL) != 0)
-                     need += 4;
-                 }
-               else
-                 need += 4;
                *local_got = allocate_got (htab, need);
                if (info->shared)
                  htab->relgot->size += (need
@@ -5564,7 +5658,7 @@ ppc_elf_relax_section (bfd *abfd,
   Elf_Internal_Rela *internal_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend;
   struct one_fixup *fixups = NULL;
-  bfd_boolean changed;
+  unsigned changes = 0;
   struct ppc_elf_link_hash_table *htab;
   bfd_size_type trampoff;
   asection *got2;
@@ -5811,6 +5905,7 @@ ppc_elf_relax_section (bfd *abfd,
          fixups = f;
 
          trampoff += size;
+         changes++;
        }
       else
        {
@@ -5861,7 +5956,6 @@ ppc_elf_relax_section (bfd *abfd,
     }
 
   /* Write out the trampolines.  */
-  changed = fixups != NULL;
   if (fixups != NULL)
     {
       const int *stub;
@@ -5927,7 +6021,7 @@ ppc_elf_relax_section (bfd *abfd,
   if (contents != NULL
       && elf_section_data (isec)->this_hdr.contents != contents)
     {
-      if (!changed && !link_info->keep_memory)
+      if (!changes && !link_info->keep_memory)
        free (contents);
       else
        {
@@ -5936,15 +6030,35 @@ ppc_elf_relax_section (bfd *abfd,
        }
     }
 
-  if (elf_section_data (isec)->relocs != internal_relocs)
+  if (changes != 0)
     {
-      if (!changed)
+      /* Append sufficient NOP relocs so we can write out relocation
+        information for the trampolines.  */
+      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,
+             isec->reloc_count * sizeof (*new_relocs));
+      for (ix = changes; ix--;)
+       {
+         irel = new_relocs + ix + isec->reloc_count;
+
+         irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
+       }
+      if (internal_relocs != elf_section_data (isec)->relocs)
        free (internal_relocs);
-      else
-       elf_section_data (isec)->relocs = internal_relocs;
+      elf_section_data (isec)->relocs = new_relocs;
+      isec->reloc_count += changes;
+      elf_section_data (isec)->rel_hdr.sh_size
+       += changes * elf_section_data (isec)->rel_hdr.sh_entsize;
     }
+  else if (elf_section_data (isec)->relocs != internal_relocs)
+    free (internal_relocs);
 
-  *again = changed;
+  *again = changes != 0;
   return TRUE;
 
  error_return:
@@ -6189,16 +6303,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
         for the final instruction stream.  */
       tls_mask = 0;
       tls_gd = 0;
-      if (IS_PPC_TLS_RELOC (r_type))
+      if (h != NULL)
+       tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
+      else if (local_got_offsets != NULL)
        {
-         if (h != NULL)
-           tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
-         else if (local_got_offsets != NULL)
-           {
-             char *lgot_masks;
-             lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
-             tls_mask = lgot_masks[r_symndx];
-           }
+         char *lgot_masks;
+         lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
+         tls_mask = lgot_masks[r_symndx];
        }
 
       /* Ensure reloc mapping code below stays sane.  */
@@ -6312,22 +6423,36 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_GOT_TLSLD16_LO:
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
            {
-             bfd_vma insn1, insn2;
+             unsigned int insn1, insn2;
              bfd_vma offset;
 
            tls_ldgd_opt:
-             offset = rel[1].r_offset;
-             insn1 = bfd_get_32 (output_bfd,
-                                 contents + rel->r_offset - d_offset);
+             offset = (bfd_vma) -1;
+             /* If not using the newer R_PPC_TLSGD/LD to mark
+                __tls_get_addr calls, we must trust that the call
+                stays with its arg setup insns, ie. that the next
+                reloc is the __tls_get_addr call associated with
+                the current reloc.  Edit both insns.  */
+             if (input_section->has_tls_get_addr_call
+                 && rel + 1 < relend
+                 && branch_reloc_hash_match (input_bfd, rel + 1,
+                                             htab->tls_get_addr))
+               offset = rel[1].r_offset;
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
+                 insn1 = bfd_get_32 (output_bfd,
+                                     contents + rel->r_offset - d_offset);
                  insn1 &= (1 << 26) - 1;
                  insn1 |= 32 << 26;    /* lwz */
-                 insn2 = 0x7c631214;   /* add 3,3,2 */
-                 rel[1].r_info
-                   = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE);
-                 rel[1].r_addend = 0;
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info
+                       = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+                                       R_PPC_NONE);
+                     insn2 = 0x7c631214;       /* add 3,3,2 */
+                     bfd_put_32 (output_bfd, insn2, contents + offset);
+                   }
                  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                            + R_PPC_GOT_TPREL16);
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -6336,7 +6461,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                {
                  /* LE */
                  insn1 = 0x3c620000;   /* addis 3,2,0 */
-                 insn2 = 0x38630000;   /* addi 3,3,0 */
                  if (tls_gd == 0)
                    {
                      /* Was an LD reloc.  */
@@ -6355,14 +6479,17 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    }
                  r_type = R_PPC_TPREL16_HA;
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
-                 rel[1].r_info = ELF32_R_INFO (r_symndx,
-                                               R_PPC_TPREL16_LO);
-                 rel[1].r_offset += d_offset;
-                 rel[1].r_addend = rel->r_addend;
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
+                     rel[1].r_offset = offset + d_offset;
+                     rel[1].r_addend = rel->r_addend;
+                     insn2 = 0x38630000;       /* addi 3,3,0 */
+                     bfd_put_32 (output_bfd, insn2, contents + offset);
+                   }
                }
              bfd_put_32 (output_bfd, insn1,
                          contents + rel->r_offset - d_offset);
-             bfd_put_32 (output_bfd, insn2, contents + offset);
              if (tls_gd == 0)
                {
                  /* We changed the symbol on an LD reloc.  Start over
@@ -6372,6 +6499,66 @@ ppc_elf_relocate_section (bfd *output_bfd,
                }
            }
          break;
+
+       case R_PPC_TLSGD:
+         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+           {
+             unsigned int insn2;
+             bfd_vma offset = rel->r_offset;
+
+             if ((tls_mask & TLS_TPRELGD) != 0)
+               {
+                 /* IE */
+                 r_type = R_PPC_NONE;
+                 insn2 = 0x7c631214;   /* add 3,3,2 */
+               }
+             else
+               {
+                 /* LE */
+                 r_type = R_PPC_TPREL16_LO;
+                 rel->r_offset += d_offset;
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+               }
+             rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+             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);
+           }
+         break;
+
+       case R_PPC_TLSLD:
+         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+           {
+             unsigned int insn2;
+
+             for (r_symndx = 0;
+                  r_symndx < symtab_hdr->sh_info;
+                  r_symndx++)
+               if (local_sections[r_symndx] == sec)
+                 break;
+             if (r_symndx >= symtab_hdr->sh_info)
+               r_symndx = 0;
+             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+             if (r_symndx != 0)
+               rel->r_addend -= (local_syms[r_symndx].st_value
+                                 + sec->output_offset
+                                 + sec->output_section->vma);
+
+             rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
+             rel->r_offset += d_offset;
+             insn2 = 0x38630000;       /* addi 3,3,0 */
+             bfd_put_32 (output_bfd, insn2,
+                         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--;
+             continue;
+           }
+         break;
        }
 
       /* Handle other relocations that tweak non-addend part of insn.  */
@@ -6424,6 +6611,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_NONE:
        case R_PPC_TLS:
+       case R_PPC_TLSGD:
+       case R_PPC_TLSLD:
        case R_PPC_EMB_MRKREF:
        case R_PPC_GNU_VTINHERIT:
        case R_PPC_GNU_VTENTRY:
@@ -6465,6 +6654,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_GOT16_LO:
        case R_PPC_GOT16_HI:
        case R_PPC_GOT16_HA:
+         tls_mask = 0;
        dogot:
          {
            /* Relocation is to the entry for this symbol in the global
@@ -6554,7 +6744,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
                    /* Generate relocs for the dynamic linker.  */
                    if ((info->shared || indx != 0)
-                       && (h == NULL
+                       && (offp == &htab->tlsld_got.offset
+                           || h == NULL
                            || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                            || h->root.type != bfd_link_hash_undefweak))
                      {
@@ -6585,7 +6776,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
                        else
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
-                       if (indx == 0)
+                       if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD))
                          {
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
@@ -6656,8 +6847,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  }
              }
 
-           relocation = htab->got->output_offset + off;
-           relocation -= htab->elf.hgot->root.u.def.value;
+           relocation = (htab->got->output_section->vma
+                         + htab->got->output_offset
+                         + off
+                         - SYM_VAL (htab->elf.hgot));
 
            /* Addends on got relocations don't make much sense.
               x+off@got is actually x@got+off, and since the got is
@@ -6797,22 +6990,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                 time.  */
              if (sreloc == NULL)
                {
-                 const char *name;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (input_bfd,
-                          elf_elfheader (input_bfd)->e_shstrndx,
-                          elf_section_data (input_section)->rel_hdr.sh_name));
-                 if (name == NULL)
+                 sreloc = _bfd_elf_get_dynamic_reloc_section
+                   (input_bfd, input_section, /*rela?*/ TRUE);
+                 if (sreloc == NULL)
                    return FALSE;
-
-                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                             && strcmp (bfd_get_section_name (input_bfd,
-                                                              input_section),
-                                        name + 5) == 0);
-
-                 sreloc = bfd_get_section_by_name (htab->elf.dynobj, name);
-                 BFD_ASSERT (sreloc != NULL);
                }
 
              skip = 0;
@@ -6947,6 +7128,17 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
            bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
            bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
+
+           /* Rewrite the reloc and convert one of the trailing nop
+              relocs to describe this relocation.  */
+           BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
+           /* The relocs are at the bottom 2 bytes */
+           rel[0].r_offset += 2;
+           memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
+           rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
+           rel[1].r_offset += 4;
+           rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
+           rel++;
          }
          continue;
 
@@ -6971,12 +7163,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
             an embedded ELF object, for which the .got section acts like the
             AIX .toc section.  */
        case R_PPC_TOC16:                       /* phony GOT16 relocations */
-         BFD_ASSERT (sec != NULL);
-         BFD_ASSERT (bfd_is_und_section (sec)
-                     || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
+         if (sec == NULL || sec->output_section == NULL)
+           {
+             unresolved_reloc = TRUE;
+             break;
+           }
+         BFD_ASSERT (strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
                      || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0);
 
-           addend -= sec->output_section->vma + sec->output_offset + 0x8000;
+         addend -= sec->output_section->vma + sec->output_offset + 0x8000;
          break;
 
        case R_PPC_PLTREL24:
@@ -7011,9 +7206,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_SDAREL16:
          {
            const char *name;
-           struct elf_link_hash_entry *sh;
 
-           BFD_ASSERT (sec != NULL);
+           if (sec == NULL || sec->output_section == NULL)
+             {
+               unresolved_reloc = TRUE;
+               break;
+             }
+
            name = bfd_get_section_name (abfd, sec->output_section);
            if (! ((CONST_STRNEQ (name, ".sdata")
                    && (name[6] == 0 || name[6] == '.'))
@@ -7028,10 +7227,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                   howto->name,
                   name);
              }
-           sh = htab->sdata[0].sym;
-           addend -= (sh->root.u.def.value
-                      + sh->root.u.def.section->output_offset
-                      + sh->root.u.def.section->output_section->vma);
+           addend -= SYM_VAL (htab->sdata[0].sym);
          }
          break;
 
@@ -7039,9 +7235,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_EMB_SDA2REL:
          {
            const char *name;
-           struct elf_link_hash_entry *sh;
 
-           BFD_ASSERT (sec != NULL);
+           if (sec == NULL || sec->output_section == NULL)
+             {
+               unresolved_reloc = TRUE;
+               break;
+             }
+
            name = bfd_get_section_name (abfd, sec->output_section);
            if (! (CONST_STRNEQ (name, ".sdata2")
                   || CONST_STRNEQ (name, ".sbss2")))
@@ -7058,10 +7258,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                ret = FALSE;
                continue;
              }
-           sh = htab->sdata[1].sym;
-           addend -= (sh->root.u.def.value
-                      + sh->root.u.def.section->output_offset
-                      + sh->root.u.def.section->output_section->vma);
+           addend -= SYM_VAL (htab->sdata[1].sym);
          }
          break;
 
@@ -7071,9 +7268,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
          {
            const char *name;
            int reg;
-           struct elf_link_hash_entry *sh;
 
-           BFD_ASSERT (sec != NULL);
+           if (sec == NULL || sec->output_section == NULL)
+             {
+               unresolved_reloc = TRUE;
+               break;
+             }
+
            name = bfd_get_section_name (abfd, sec->output_section);
            if (((CONST_STRNEQ (name, ".sdata")
                  && (name[6] == 0 || name[6] == '.'))
@@ -7081,28 +7282,19 @@ ppc_elf_relocate_section (bfd *output_bfd,
                     && (name[5] == 0 || name[5] == '.'))))
              {
                reg = 13;
-               sh = htab->sdata[0].sym;
-               addend -= (sh->root.u.def.value
-                          + sh->root.u.def.section->output_offset
-                          + sh->root.u.def.section->output_section->vma);
+               addend -= SYM_VAL (htab->sdata[0].sym);
              }
-
            else if (CONST_STRNEQ (name, ".sdata2")
                     || CONST_STRNEQ (name, ".sbss2"))
              {
                reg = 2;
-               sh = htab->sdata[1].sym;
-               addend -= (sh->root.u.def.value
-                          + sh->root.u.def.section->output_offset
-                          + sh->root.u.def.section->output_section->vma);
+               addend -= SYM_VAL (htab->sdata[1].sym);
              }
-
            else if (strcmp (name, ".PPC.EMB.sdata0") == 0
                     || strcmp (name, ".PPC.EMB.sbss0") == 0)
              {
                reg = 0;
              }
-
            else
              {
                (*_bfd_error_handler)
@@ -7132,7 +7324,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_SECTOFF_LO:
        case R_PPC_SECTOFF_HI:
        case R_PPC_SECTOFF_HA:
-         BFD_ASSERT (sec != NULL);
+         if (sec == NULL || sec->output_section == NULL)
+           {
+             unresolved_reloc = TRUE;
+             break;
+           }
          addend -= sec->output_section->vma;
          break;
 
@@ -7347,31 +7543,22 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                /* Fill in the .plt on VxWorks.  */
                if (info->shared)
                  {
-                   bfd_vma got_offset_hi = (got_offset >> 16)
-                                           + ((got_offset & 0x8000) >> 15);
-
                    bfd_put_32 (output_bfd,
-                               plt_entry[0] | (got_offset_hi & 0xffff),
+                               plt_entry[0] | PPC_HA (got_offset),
                                htab->plt->contents + ent->plt.offset + 0);
                    bfd_put_32 (output_bfd,
-                               plt_entry[1] | (got_offset & 0xffff),
+                               plt_entry[1] | PPC_LO (got_offset),
                                htab->plt->contents + ent->plt.offset + 4);
                  }
                else
                  {
-                   bfd_vma got_loc
-                     = (got_offset
-                        + htab->elf.hgot->root.u.def.value
-                        + htab->elf.hgot->root.u.def.section->output_offset
-                        + htab->elf.hgot->root.u.def.section->output_section->vma);
-                   bfd_vma got_loc_hi = (got_loc >> 16)
-                                        + ((got_loc & 0x8000) >> 15);
+                   bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
 
                    bfd_put_32 (output_bfd,
-                               plt_entry[0] | (got_loc_hi & 0xffff),
+                               plt_entry[0] | PPC_HA (got_loc),
                                htab->plt->contents + ent->plt.offset + 0);
                    bfd_put_32 (output_bfd,
-                               plt_entry[1] | (got_loc & 0xffff),
+                               plt_entry[1] | PPC_LO (got_loc),
                                htab->plt->contents + ent->plt.offset + 4);
                  }
 
@@ -7531,9 +7718,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                         + ent->sec->output_section->vma
                         + ent->sec->output_offset);
                else if (htab->elf.hgot != NULL)
-                 got = (htab->elf.hgot->root.u.def.value
-                        + htab->elf.hgot->root.u.def.section->output_section->vma
-                        + htab->elf.hgot->root.u.def.section->output_offset);
+                 got = SYM_VAL (htab->elf.hgot);
 
                plt -= got;
 
@@ -7599,9 +7784,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
        s = htab->relbss;
       BFD_ASSERT (s != NULL);
 
-      rela.r_offset = (h->root.u.def.value
-                      + h->root.u.def.section->output_section->vma
-                      + h->root.u.def.section->output_offset);
+      rela.r_offset = SYM_VAL (h);
       rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
       rela.r_addend = 0;
       loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
@@ -7651,7 +7834,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   asection *splt;
   struct ppc_elf_link_hash_table *htab;
   bfd_vma got;
-  bfd * dynobj;
+  bfd *dynobj;
+  bfd_boolean ret = TRUE;
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
@@ -7667,9 +7851,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
   got = 0;
   if (htab->elf.hgot != NULL)
-    got = (htab->elf.hgot->root.u.def.value
-          + htab->elf.hgot->root.u.def.section->output_section->vma
-          + htab->elf.hgot->root.u.def.section->output_offset);
+    got = SYM_VAL (htab->elf.hgot);
 
   if (htab->elf.dynamic_sections_created)
     {
@@ -7729,21 +7911,41 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
     }
 
-  /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can
-     easily find the address of the _GLOBAL_OFFSET_TABLE_.  */
   if (htab->got != NULL)
     {
-      unsigned char *p = htab->got->contents;
-      bfd_vma val;
+      if (htab->elf.hgot->root.u.def.section == htab->got
+         || htab->elf.hgot->root.u.def.section == htab->sgotplt)
+       {
+         unsigned char *p = htab->elf.hgot->root.u.def.section->contents;
 
-      p += htab->elf.hgot->root.u.def.value;
-      if (htab->plt_type == PLT_OLD)
-       bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4);
+         p += htab->elf.hgot->root.u.def.value;
+         if (htab->plt_type == PLT_OLD)
+           {
+             /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4
+                so that a function can easily find the address of
+                _GLOBAL_OFFSET_TABLE_.  */
+             BFD_ASSERT (htab->elf.hgot->root.u.def.value - 4
+                         < htab->elf.hgot->root.u.def.section->size);
+             bfd_put_32 (output_bfd, 0x4e800021, p - 4);
+           }
 
-      val = 0;
-      if (sdyn != NULL)
-       val = sdyn->output_section->vma + sdyn->output_offset;
-      bfd_put_32 (output_bfd, val, p);
+         if (sdyn != NULL)
+           {
+             bfd_vma val = sdyn->output_section->vma + sdyn->output_offset;
+             BFD_ASSERT (htab->elf.hgot->root.u.def.value
+                         < htab->elf.hgot->root.u.def.section->size);
+             bfd_put_32 (output_bfd, val, p);
+           }
+       }
+      else
+       {
+         (*_bfd_error_handler) (_("%s not defined in linker created %s"),
+                                htab->elf.hgot->root.root.string,
+                                (htab->sgotplt != NULL
+                                 ? htab->sgotplt->name : htab->got->name));
+         bfd_set_error (bfd_error_bad_value);
+         ret = FALSE;
+       }
 
       elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
     }
@@ -7758,15 +7960,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
       if (!info->shared)
        {
-         bfd_vma got_value =
-           (htab->elf.hgot->root.u.def.section->output_section->vma
-            + htab->elf.hgot->root.u.def.section->output_offset
-            + htab->elf.hgot->root.u.def.value);
-         bfd_vma got_hi = (got_value >> 16) + ((got_value & 0x8000) >> 15);
+         bfd_vma got_value = SYM_VAL (htab->elf.hgot);
 
-         bfd_put_32 (output_bfd, plt_entry[0] | (got_hi & 0xffff),
+         bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_value),
                      splt->contents +  0);
-         bfd_put_32 (output_bfd, plt_entry[1] | (got_value & 0xffff),
+         bfd_put_32 (output_bfd, plt_entry[1] | PPC_LO (got_value),
                      splt->contents +  4);
        }
       else
@@ -8031,7 +8229,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
     }
 
-  return TRUE;
+  return ret;
 }
 \f
 #define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
This page took 0.039398 seconds and 4 git commands to generate.