Apply Bruno de Bus's patch to record the ARM mapping symbol state on a per-
[deliverable/binutils-gdb.git] / bfd / elf32-xtensa.c
index cec239ebfdb575eeee83027cadb0f503e5949145..b7639b7508b77e55c064a32d2c1873f31523f3e5 100644 (file)
@@ -1,5 +1,5 @@
 /* Xtensa-specific support for 32-bit ELF.
-   Copyright 2003 Free Software Foundation, Inc.
+   Copyright 2003, 2004 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -60,7 +60,7 @@ static bfd_boolean elf_xtensa_adjust_dynamic_symbol
 static bfd_boolean elf_xtensa_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static bfd_boolean elf_xtensa_modify_segment_map
-  PARAMS ((bfd *));
+  PARAMS ((bfd *, struct bfd_link_info *));
 static bfd_boolean elf_xtensa_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
           Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
@@ -619,8 +619,6 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
-  property_table_entry *lit_table;
-  int ltblsize;
 
   if (info->relocatable)
     return TRUE;
@@ -628,11 +626,6 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
 
-  ltblsize = xtensa_read_table_entries (abfd, sec, &lit_table,
-                                       XTENSA_LIT_SEC_NAME);
-  if (ltblsize < 0)
-    return FALSE;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -669,11 +662,6 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
 
          if ((sec->flags & SEC_ALLOC) != 0)
            {
-             if ((sec->flags & SEC_READONLY) != 0
-                 && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
-                                                 sec->vma + rel->r_offset))
-               h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
-
              if (h->got.refcount <= 0)
                h->got.refcount = 1;
              else
@@ -689,11 +677,6 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
 
          if ((sec->flags & SEC_ALLOC) != 0)
            {
-             if ((sec->flags & SEC_READONLY) != 0
-                 && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
-                                                 sec->vma + rel->r_offset))
-               h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
-
              if (h->plt.refcount <= 0)
                {
                  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
@@ -736,14 +719,6 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
                }
              local_got_refcounts[r_symndx] += 1;
-
-             /* If the relocation is not inside the GOT, the DF_TEXTREL
-                flag needs to be set.  */
-             if (info->shared
-                 && (sec->flags & SEC_READONLY) != 0
-                 && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
-                                                 sec->vma + rel->r_offset))
-               info->flags |= DF_TEXTREL;
            }
          break;
 
@@ -758,14 +733,14 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
        case R_XTENSA_GNU_VTINHERIT:
          /* This relocation describes the C++ object vtable hierarchy.
             Reconstruct it for later use during GC.  */
-         if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+         if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
            return FALSE;
          break;
 
        case R_XTENSA_GNU_VTENTRY:
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
-         if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
 
@@ -774,7 +749,6 @@ elf_xtensa_check_relocs (abfd, info, sec, relocs)
        }
     }
 
-  free (lit_table);
   return TRUE;
 }
 
@@ -1044,7 +1018,6 @@ elf_xtensa_make_sym_local (info, h)
   else
     {
       /* Don't need any dynamic relocations at all.  */
-      h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
       h->plt.refcount = 0;
       h->got.refcount = 0;
     }
@@ -1064,11 +1037,6 @@ elf_xtensa_fix_refcounts (h, arg)
   if (! xtensa_elf_dynamic_symbol_p (h, info))
     elf_xtensa_make_sym_local (info, h);
 
-  /* If the symbol has a relocation outside the GOT, set the
-     DF_TEXTREL flag.  */
-  if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) != 0)
-    info->flags |= DF_TEXTREL;
-
   return TRUE;
 }
 
@@ -1366,7 +1334,7 @@ elf_xtensa_size_dynamic_sections (output_bfd, info)
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
 #define add_dynamic_entry(TAG, VAL) \
-  bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
       if (! info->shared)
        {
@@ -1391,12 +1359,6 @@ elf_xtensa_size_dynamic_sections (output_bfd, info)
            return FALSE;
        }
 
-      if ((info->flags & DF_TEXTREL) != 0)
-       {
-         if (!add_dynamic_entry (DT_TEXTREL, 0))
-           return FALSE;
-       }
-
       if (!add_dynamic_entry (DT_XTENSA_GOT_LOC_OFF, 0)
          || !add_dynamic_entry (DT_XTENSA_GOT_LOC_SZ, 0))
        return FALSE;
@@ -1415,8 +1377,9 @@ elf_xtensa_size_dynamic_sections (output_bfd, info)
    this and it probably ought to be moved into elf.c as well.  */
 
 static bfd_boolean
-elf_xtensa_modify_segment_map (abfd)
+elf_xtensa_modify_segment_map (abfd, info)
      bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
 {
   struct elf_segment_map **m_p;
 
@@ -1713,7 +1676,7 @@ bfd_elf_xtensa_reloc (abfd, reloc_entry, symbol, data, input_section,
                              / bfd_octets_per_byte (abfd)))
     return bfd_reloc_outofrange;
 
-  /* Work out which section the relocation is targetted at and the
+  /* Work out which section the relocation is targeted at and the
      initial relocation command value.  */
 
   /* Get symbol value.  (Common symbols are special.)  */
@@ -1850,6 +1813,8 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd,
   struct elf_link_hash_entry **sym_hashes;
   asection *srelgot, *srelplt;
   bfd *dynobj;
+  property_table_entry *lit_table = 0;
+  int ltblsize = 0;
   char *error_message = NULL;
 
   if (xtensa_default_isa == NULL)
@@ -1867,6 +1832,14 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd,
       srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
     }
 
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      ltblsize = xtensa_read_table_entries (input_bfd, input_section,
+                                           &lit_table, XTENSA_LIT_SEC_NAME);
+      if (ltblsize < 0)
+       return FALSE;
+    }
+
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
@@ -1992,10 +1965,10 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd,
        }
       else
        {
-         RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx,
-                                  symtab_hdr, relocation, sec,
-                                  unresolved_reloc, info,
-                                  warned);
+         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+                                  r_symndx, symtab_hdr, sym_hashes,
+                                  h, sec, relocation,
+                                  unresolved_reloc, warned);
 
          if (relocation == 0
              && !unresolved_reloc
@@ -2067,6 +2040,21 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd,
                  outrel.r_offset += (input_section->output_section->vma
                                      + input_section->output_offset);
 
+                 /* Complain if the relocation is in a read-only section
+                    and not in a literal pool.  */
+                 if ((input_section->flags & SEC_READONLY) != 0
+                     && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
+                                                     input_section->vma
+                                                     + rel->r_offset))
+                   {
+                     error_message =
+                       _("dynamic relocation in read-only section");
+                     if (!((*info->callbacks->reloc_dangerous)
+                           (info, error_message, input_bfd, input_section,
+                            rel->r_offset)))
+                       return FALSE;
+                   }
+
                  if (dynamic_symbol)
                    {
                      outrel.r_addend = rel->r_addend;
@@ -2154,6 +2142,9 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd,
        }
     }
 
+  if (lit_table)
+    free (lit_table);
+
   return TRUE;
 }
 
@@ -2729,7 +2720,7 @@ elf_xtensa_discard_info_for_section (abfd, cookie, info, sec)
       while (cookie->rel < cookie->relend
             && cookie->rel->r_offset == offset)
        {
-         if (_bfd_elf32_reloc_symbol_deleted_p (offset, cookie))
+         if (bfd_elf_reloc_symbol_deleted_p (offset, cookie))
            {
              /* Remove the table entry.  (If the reloc type is NONE, then
                 the entry has already been merged with another and deleted
@@ -3440,7 +3431,7 @@ struct value_map_hash_table_struct
 
 
 static bfd_boolean is_same_value
-  PARAMS ((const literal_value *, const literal_value *));
+  PARAMS ((const literal_value *, const literal_value *, bfd_boolean));
 static value_map_hash_table *value_map_hash_table_init
   PARAMS ((void));
 static unsigned hash_literal_value
@@ -3448,16 +3439,20 @@ static unsigned hash_literal_value
 static unsigned hash_bfd_vma
   PARAMS ((bfd_vma));
 static value_map *get_cached_value
-  PARAMS ((value_map_hash_table *, const literal_value *));
+  PARAMS ((value_map_hash_table *, const literal_value *, bfd_boolean));
 static value_map *add_value_map
-  PARAMS ((value_map_hash_table *, const literal_value *, const r_reloc *));
+  PARAMS ((value_map_hash_table *, const literal_value *, const r_reloc *,
+          bfd_boolean));
 
 
 static bfd_boolean
-is_same_value (src1, src2)
+is_same_value (src1, src2, final_static_link)
      const literal_value *src1;
      const literal_value *src2;
+     bfd_boolean final_static_link;
 {
+  struct elf_link_hash_entry *h1, *h2;
+
   if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) 
     return FALSE;
 
@@ -3475,8 +3470,14 @@ is_same_value (src1, src2)
   if (src1->value != src2->value)
     return FALSE;
   
-  /* Now check for the same section and the same elf_hash.  */
-  if (r_reloc_is_defined (&src1->r_rel))
+  /* Now check for the same section (if defined) or the same elf_hash
+     (if undefined or weak).  */
+  h1 = r_reloc_get_hash_entry (&src1->r_rel);
+  h2 = r_reloc_get_hash_entry (&src2->r_rel);
+  if (r_reloc_is_defined (&src1->r_rel)
+      && (final_static_link
+         || ((!h1 || h1->root.type != bfd_link_hash_defweak)
+             && (!h2 || h2->root.type != bfd_link_hash_defweak))))
     {
       if (r_reloc_get_section (&src1->r_rel)
          != r_reloc_get_section (&src2->r_rel))
@@ -3484,11 +3485,8 @@ is_same_value (src1, src2)
     }
   else
     {
-      if (r_reloc_get_hash_entry (&src1->r_rel)
-         != r_reloc_get_hash_entry (&src2->r_rel))
-       return FALSE;
-
-      if (r_reloc_get_hash_entry (&src1->r_rel) == 0)
+      /* Require that the hash entries (i.e., symbols) be identical.  */
+      if (h1 != h2 || h1 == 0)
        return FALSE;
     }
 
@@ -3549,9 +3547,10 @@ hash_literal_value (src)
 /* Check if the specified literal_value has been seen before.  */
 
 static value_map *
-get_cached_value (map, val)
+get_cached_value (map, val, final_static_link)
      value_map_hash_table *map;
      const literal_value *val;
+     bfd_boolean final_static_link;
 {
   value_map *map_e;
   value_map *bucket;
@@ -3562,7 +3561,7 @@ get_cached_value (map, val)
   bucket = map->buckets[idx];
   for (map_e = bucket; map_e; map_e = map_e->next)
     {
-      if (is_same_value (&map_e->val, val))
+      if (is_same_value (&map_e->val, val, final_static_link))
        return map_e;
     }
   return NULL;
@@ -3573,17 +3572,18 @@ get_cached_value (map, val)
    already has an entry here.  */
 
 static value_map *
-add_value_map (map, val, loc)
+add_value_map (map, val, loc, final_static_link)
      value_map_hash_table *map;
      const literal_value *val;
      const r_reloc *loc;
+     bfd_boolean final_static_link;
 {
   value_map **bucket_p;
   unsigned idx;
 
   value_map *val_e = (value_map *) bfd_zmalloc (sizeof (value_map));
 
-  BFD_ASSERT (get_cached_value (map, val) == NULL);
+  BFD_ASSERT (get_cached_value (map, val, final_static_link) == NULL);
   val_e->val = *val;
   val_e->loc = *loc;
 
@@ -4170,7 +4170,7 @@ analyze_relocations (link_info)
    expensive and unnecessary unless the target section is actually going
    to be relaxed.  This pass identifies all such sections by checking if
    they have L32Rs pointing to them.  In the process, the total number
-   of relocations targetting each section is also counted so that we
+   of relocations targeting each section is also counted so that we
    know how much space to allocate for source_relocs against each
    relaxable literal section.  */
 
@@ -4489,6 +4489,7 @@ remove_literals (abfd, sec, link_info, values)
   bfd_byte *contents;
   Elf_Internal_Rela *internal_relocs;
   source_reloc *src_relocs;
+  bfd_boolean final_static_link;
   bfd_boolean ok = TRUE;
   int i;
 
@@ -4509,6 +4510,10 @@ remove_literals (abfd, sec, link_info, values)
       goto error_return;
     }
 
+  final_static_link =
+    (!link_info->relocatable
+     && !elf_hash_table (link_info)->dynamic_sections_created);
+
   /* Sort the source_relocs by target offset.  */
   src_relocs = relax_info->src_relocs;
   qsort (src_relocs, relax_info->src_count,
@@ -4561,7 +4566,7 @@ remove_literals (abfd, sec, link_info, values)
       val.value = bfd_get_32 (abfd, contents + rel->r_rel.target_offset);
           
       /* Check if we've seen another literal with the same value.  */
-      val_map = get_cached_value (values, &val);
+      val_map = get_cached_value (values, &val, final_static_link);
       if (val_map != NULL) 
        {
          /* First check that THIS and all the other relocs to this
@@ -4584,7 +4589,7 @@ remove_literals (abfd, sec, link_info, values)
        {
          /* This is the first time we've seen this literal value.  */
          BFD_ASSERT (sec == r_reloc_get_section (&rel->r_rel));
-         add_value_map (values, &val, &rel->r_rel);
+         add_value_map (values, &val, &rel->r_rel, final_static_link);
        }
     }
 
@@ -5824,7 +5829,6 @@ static struct bfd_elf_special_section const elf_xtensa_special_sections[]=
 
 #define elf_info_to_howto                   elf_xtensa_info_to_howto_rela
 
-#define bfd_elf32_bfd_final_link            bfd_elf32_bfd_final_link
 #define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data
 #define bfd_elf32_new_section_hook          elf_xtensa_new_section_hook
 #define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data
This page took 0.028236 seconds and 4 git commands to generate.