* elf32-xtensa.c (elf_xtensa_relocate_section): Remove updates of
[binutils-gdb.git] / bfd / elf32-xtensa.c
index 2f832566fe6250ea68f74f84153a3398a9a5cd45..dac6896a015293e4a8862ccc2c17817a0944a6c7 100644 (file)
@@ -5,7 +5,7 @@
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of the
+   published by the Free Software Foundation; either version 3 of the
    License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful, but
@@ -944,7 +944,9 @@ elf_xtensa_check_relocs (bfd *abfd,
        case R_XTENSA_GNU_VTENTRY:
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
-         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         BFD_ASSERT (h != NULL);
+         if (h != NULL
+             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
 
@@ -2093,7 +2095,6 @@ elf_xtensa_relocate_section (bfd *output_bfd,
              if (!do_fix_for_relocatable_link (rel, input_bfd, input_section,
                                                contents))
                return FALSE;
-             r_type = ELF32_R_TYPE (rel->r_info);
            }
 
          if (r_type == R_XTENSA_ASM_SIMPLIFY)
@@ -2163,10 +2164,6 @@ elf_xtensa_relocate_section (bfd *output_bfd,
          /* Check if this references a section in another input file.  */
          do_fix_for_final_link (rel, input_bfd, input_section, contents,
                                 &relocation);
-
-         /* Update some already cached values.  */
-         r_type = ELF32_R_TYPE (rel->r_info);
-         howto = &elf_howto_table[r_type];
        }
 
       /* Sanity check the address.  */
@@ -2649,19 +2646,19 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd,
          break;
 
        case DT_XTENSA_GOT_LOC_OFF:
-         dyn.d_un.d_ptr = htab->sgotloc->vma;
+         dyn.d_un.d_ptr = htab->sgotloc->output_section->vma;
          break;
 
        case DT_PLTGOT:
-         dyn.d_un.d_ptr = htab->sgot->vma;
+         dyn.d_un.d_ptr = htab->sgot->output_section->vma;
          break;
 
        case DT_JMPREL:
-         dyn.d_un.d_ptr = htab->srelplt->vma;
+         dyn.d_un.d_ptr = htab->srelplt->output_section->vma;
          break;
 
        case DT_PLTRELSZ:
-         dyn.d_un.d_val = htab->srelplt->size;
+         dyn.d_un.d_val = htab->srelplt->output_section->size;
          break;
 
        case DT_RELASZ:
@@ -2672,7 +2669,7 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd,
             for .rela.plt to follow all other relocation sections, we
             don't have to worry about changing the DT_RELA entry.  */
          if (htab->srelplt)
-           dyn.d_un.d_val -= htab->srelplt->size;
+           dyn.d_un.d_val -= htab->srelplt->output_section->size;
          break;
        }
 
@@ -4778,20 +4775,45 @@ text_action_add_literal (text_action_list *l,
 }
 
 
-static bfd_vma 
-offset_with_removed_text (text_action_list *action_list, bfd_vma offset)
+/* Find the total offset adjustment for the relaxations specified by
+   text_actions, beginning from a particular starting action.  This is
+   typically used from offset_with_removed_text to search an entire list of
+   actions, but it may also be called directly when adjusting adjacent offsets
+   so that each search may begin where the previous one left off.  */
+
+static int
+removed_by_actions (text_action **p_start_action,
+                   bfd_vma offset,
+                   bfd_boolean before_fill)
 {
   text_action *r;
   int removed = 0;
 
-  for (r = action_list->head; r && r->offset <= offset; r = r->next)
+  r = *p_start_action;
+  while (r)
     {
-      if (r->offset < offset
-         || (r->action == ta_fill && r->removed_bytes < 0))
-       removed += r->removed_bytes;
+      if (r->offset > offset)
+       break;
+
+      if (r->offset == offset
+         && (before_fill || r->action != ta_fill || r->removed_bytes >= 0))
+       break;
+
+      removed += r->removed_bytes;
+
+      r = r->next;
     }
 
-  return (offset - removed);
+  *p_start_action = r;
+  return removed;
+}
+
+
+static bfd_vma 
+offset_with_removed_text (text_action_list *action_list, bfd_vma offset)
+{
+  text_action *r = action_list->head;
+  return offset - removed_by_actions (&r, offset, FALSE);
 }
 
 
@@ -4808,20 +4830,6 @@ action_list_count (text_action_list *action_list)
 }
 
 
-static bfd_vma
-offset_with_removed_text_before_fill (text_action_list *action_list,
-                                     bfd_vma offset)
-{
-  text_action *r;
-  int removed = 0;
-
-  for (r = action_list->head; r && r->offset < offset; r = r->next)
-    removed += r->removed_bytes;
-
-  return (offset - removed);
-}
-
-
 /* The find_insn_action routine will only find non-fill actions.  */
 
 static text_action *
@@ -5119,7 +5127,6 @@ struct reloc_bfd_fix_struct
   bfd_vma src_offset;
   unsigned src_type;                   /* Relocation type.  */
   
-  bfd *target_abfd;
   asection *target_sec;
   bfd_vma target_offset;
   bfd_boolean translated;
@@ -5132,7 +5139,6 @@ static reloc_bfd_fix *
 reloc_bfd_fix_init (asection *src_sec,
                    bfd_vma src_offset,
                    unsigned src_type,
-                   bfd *target_abfd,
                    asection *target_sec,
                    bfd_vma target_offset,
                    bfd_boolean translated)
@@ -5143,7 +5149,6 @@ reloc_bfd_fix_init (asection *src_sec,
   fix->src_sec = src_sec;
   fix->src_offset = src_offset;
   fix->src_type = src_type;
-  fix->target_abfd = target_abfd;
   fix->target_sec = target_sec;
   fix->target_offset = target_offset;
   fix->translated = translated;
@@ -5541,7 +5546,7 @@ extend_ebb_bounds_forward (ebb_t *ebb)
 
       new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1];
       if (((new_entry->flags & XTENSA_PROP_INSN) == 0)
-         || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0)
+         || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0)
          || ((the_entry->flags & XTENSA_PROP_ALIGN) != 0))
        break;
 
@@ -5614,7 +5619,7 @@ extend_ebb_bounds_backward (ebb_t *ebb)
 
       new_entry = &ebb->ptbl[ebb->start_ptbl_idx - 1];
       if ((new_entry->flags & XTENSA_PROP_INSN) == 0
-         || ((new_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) != 0)
+         || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0)
          || ((new_entry->flags & XTENSA_PROP_ALIGN) != 0))
        return TRUE;
       if (new_entry->address + new_entry->size != the_entry->address)
@@ -5822,7 +5827,8 @@ static bfd_boolean compute_removed_literals
 static Elf_Internal_Rela *get_irel_at_offset
   (asection *, Elf_Internal_Rela *, bfd_vma);
 static bfd_boolean is_removable_literal 
-  (const source_reloc *, int, const source_reloc *, int);
+  (const source_reloc *, int, const source_reloc *, int, asection *,
+   property_table_entry *, int);
 static bfd_boolean remove_dead_literal
   (bfd *, asection *, struct bfd_link_info *, Elf_Internal_Rela *,
    Elf_Internal_Rela *, source_reloc *, property_table_entry *, int); 
@@ -6480,7 +6486,7 @@ compute_text_actions (bfd *abfd,
          the_entry++;
        }
 
-      if (the_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM)
+      if (the_entry->flags & XTENSA_PROP_NO_TRANSFORM)
          /* NO_REORDER is OK */
        continue;
 
@@ -6673,14 +6679,14 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table)
            goto decode_error;
 
          if ((entry->flags & XTENSA_PROP_INSN_NO_DENSITY) == 0
-             && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+             && (entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0
              && can_narrow_instruction (slotbuf, fmt, opcode) != 0)
            {
              /* Add an instruction narrow action.  */
              ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0,
                                  ta_narrow_insn, offset, 0, FALSE);
            }
-         else if ((entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM) == 0
+         else if ((entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0
                   && can_widen_instruction (slotbuf, fmt, opcode) != 0
                   && ! prev_instr_is_a_loop (ebb->contents,
                                              ebb->content_length, offset))
@@ -6925,6 +6931,8 @@ compute_ebb_actions (ebb_constraint *ebb_table)
                      bad_alignment = FALSE;
                      break;
                    }
+                 if (new_action->do_action)
+                   removed_bytes += new_action->removed_bytes;
                }
              if (!bad_alignment)
                {
@@ -7430,7 +7438,8 @@ compute_removed_literals (bfd *abfd,
       /* Check if the relocation was from an L32R that is being removed
         because a CALLX was converted to a direct CALL, and check if
         there are no other relocations to the literal.  */
-      if (is_removable_literal (rel, i, src_relocs, relax_info->src_count))
+      if (is_removable_literal (rel, i, src_relocs, relax_info->src_count, 
+                               sec, prop_table, ptblsize))
        {
          if (!remove_dead_literal (abfd, sec, link_info, internal_relocs,
                                    irel, rel, prop_table, ptblsize))
@@ -7514,12 +7523,22 @@ bfd_boolean
 is_removable_literal (const source_reloc *rel,
                      int i,
                      const source_reloc *src_relocs,
-                     int src_count)
+                     int src_count,
+                     asection *sec,
+                     property_table_entry *prop_table,
+                     int ptblsize)
 {
   const source_reloc *curr_rel;
+  property_table_entry *entry;
+
   if (!rel->is_null)
     return FALSE;
   
+  entry = elf_xtensa_find_property_entry (prop_table, ptblsize, 
+                                         sec->vma + rel->r_rel.target_offset);
+  if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM))
+    return FALSE;
+
   for (++i; i < src_count; ++i)
     {
       curr_rel = &src_relocs[i];
@@ -7809,7 +7828,7 @@ coalesce_shared_literal (asection *sec,
 
   entry = elf_xtensa_find_property_entry
     (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset);
-  if (entry && (entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM))
+  if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM))
     return TRUE;
 
   /* Mark that the literal will be coalesced.  */
@@ -8215,7 +8234,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
              addend_displacement =
                new_reloc.target_offset + new_reloc.virtual_offset;
 
-             fix = reloc_bfd_fix_init (sec, source_offset, r_type, 0,
+             fix = reloc_bfd_fix_init (sec, source_offset, r_type,
                                        r_reloc_get_section (&new_reloc),
                                        addend_displacement, TRUE);
              add_fix (sec, fix);
@@ -8768,7 +8787,7 @@ move_literal (bfd *abfd,
 
       /* Currently, we cannot move relocations during a relocatable link.  */
       BFD_ASSERT (!link_info->relocatable);
-      fix = reloc_bfd_fix_init (sec, offset, r_type, r_rel->abfd,
+      fix = reloc_bfd_fix_init (sec, offset, r_type,
                                r_reloc_get_section (r_rel),
                                r_rel->target_offset + r_rel->virtual_offset,
                                FALSE);
@@ -8930,14 +8949,16 @@ relax_property_section (bfd *abfd,
                  || target_relax_info->is_relaxable_asm_section ))
            {
              /* Translate the relocation's destination.  */
-             bfd_vma new_offset, new_end_offset;
+             bfd_vma old_offset = val.r_rel.target_offset;
+             bfd_vma new_offset;
              long old_size, new_size;
-
-             new_offset = offset_with_removed_text
-               (&target_relax_info->action_list, val.r_rel.target_offset);
+             text_action *act = target_relax_info->action_list.head;
+             new_offset = old_offset -
+               removed_by_actions (&act, old_offset, FALSE);
 
              /* Assert that we are not out of bounds.  */
              old_size = bfd_get_32 (abfd, size_p);
+             new_size = old_size;
 
              if (old_size == 0)
                {
@@ -8949,39 +8970,34 @@ relax_property_section (bfd *abfd,
                     offset before or after the fill address depending
                     on whether the expanding unreachable entry
                     preceeds it.  */
-                 if (last_zfill_target_sec
-                     && last_zfill_target_sec == target_sec
-                     && last_zfill_target_offset == val.r_rel.target_offset)
-                   new_end_offset = new_offset;
-                 else
+                 if (last_zfill_target_sec == 0
+                     || last_zfill_target_sec != target_sec
+                     || last_zfill_target_offset != old_offset)
                    {
-                     new_end_offset = new_offset;
-                     new_offset = offset_with_removed_text_before_fill
-                       (&target_relax_info->action_list,
-                        val.r_rel.target_offset);
+                     bfd_vma new_end_offset = new_offset;
+
+                     /* Recompute the new_offset, but this time don't
+                        include any fill inserted by relaxation.  */
+                     act = target_relax_info->action_list.head;
+                     new_offset = old_offset -
+                       removed_by_actions (&act, old_offset, TRUE);
 
                      /* If it is not unreachable and we have not yet
                         seen an unreachable at this address, place it
                         before the fill address.  */
-                     if (!flags_p
-                         || (bfd_get_32 (abfd, flags_p)
-                             & XTENSA_PROP_UNREACHABLE) == 0)
-                       new_end_offset = new_offset;
-                     else
+                     if (flags_p && (bfd_get_32 (abfd, flags_p)
+                                     & XTENSA_PROP_UNREACHABLE) != 0)
                        {
+                         new_size = new_end_offset - new_offset;
+
                          last_zfill_target_sec = target_sec;
-                         last_zfill_target_offset = val.r_rel.target_offset;
+                         last_zfill_target_offset = old_offset;
                        }
                    }
                }
              else
-               {
-                 new_end_offset = offset_with_removed_text_before_fill
-                   (&target_relax_info->action_list,
-                    val.r_rel.target_offset + old_size);
-               }
-
-             new_size = new_end_offset - new_offset;
+               new_size -=
+                   removed_by_actions (&act, old_offset + old_size, TRUE);
 
              if (new_size != old_size)
                {
@@ -8989,9 +9005,9 @@ relax_property_section (bfd *abfd,
                  pin_contents (sec, contents);
                }
 
-             if (new_offset != val.r_rel.target_offset)
+             if (new_offset != old_offset)
                {
-                 bfd_vma diff = new_offset - val.r_rel.target_offset;
+                 bfd_vma diff = new_offset - old_offset;
                  irel->r_addend += diff;
                  pin_internal_relocs (sec, internal_relocs);
                }
@@ -9244,19 +9260,14 @@ relax_section_symbols (bfd *abfd, asection *sec)
 
       if (isym->st_shndx == sec_shndx)
        {
-         bfd_vma new_address = offset_with_removed_text
-           (&relax_info->action_list, isym->st_value);
-         bfd_vma new_size = isym->st_size;
+         text_action *act = relax_info->action_list.head;
+         bfd_vma orig_addr = isym->st_value;
 
-         if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC)
-           {
-             bfd_vma new_end = offset_with_removed_text
-               (&relax_info->action_list, isym->st_value + isym->st_size);
-             new_size = new_end - new_address;
-           }
+         isym->st_value -= removed_by_actions (&act, orig_addr, FALSE);
 
-         isym->st_value = new_address;
-         isym->st_size = new_size;
+         if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC)
+           isym->st_size -=
+             removed_by_actions (&act, orig_addr + isym->st_size, FALSE);
        }
     }
 
@@ -9274,20 +9285,15 @@ relax_section_symbols (bfd *abfd, asection *sec)
           || sym_hash->root.type == bfd_link_hash_defweak)
          && sym_hash->root.u.def.section == sec)
        {
-         bfd_vma new_address = offset_with_removed_text
-           (&relax_info->action_list, sym_hash->root.u.def.value);
-         bfd_vma new_size = sym_hash->size;
+         text_action *act = relax_info->action_list.head;
+         bfd_vma orig_addr = sym_hash->root.u.def.value;
 
-         if (sym_hash->type == STT_FUNC)
-           {
-             bfd_vma new_end = offset_with_removed_text
-               (&relax_info->action_list,
-                sym_hash->root.u.def.value + sym_hash->size);
-             new_size = new_end - new_address;
-           }
+         sym_hash->root.u.def.value -=
+           removed_by_actions (&act, orig_addr, FALSE);
 
-         sym_hash->root.u.def.value = new_address;
-         sym_hash->size = new_size;
+         if (sym_hash->type == STT_FUNC)
+           sym_hash->size -=
+             removed_by_actions (&act, orig_addr + sym_hash->size, FALSE);
        }
     }
 
@@ -9735,12 +9741,12 @@ xtensa_get_property_predef_flags (asection *sec)
 {
   if (xtensa_is_insntable_section (sec))
     return (XTENSA_PROP_INSN
-           | XTENSA_PROP_INSN_NO_TRANSFORM
+           | XTENSA_PROP_NO_TRANSFORM
            | XTENSA_PROP_INSN_NO_REORDER);
 
   if (xtensa_is_littable_section (sec))
     return (XTENSA_PROP_LITERAL
-           | XTENSA_PROP_INSN_NO_TRANSFORM
+           | XTENSA_PROP_NO_TRANSFORM
            | XTENSA_PROP_INSN_NO_REORDER);
 
   return 0;
@@ -9793,6 +9799,11 @@ xtensa_callback_required_dependence (bfd *abfd,
       (*callback) (sec, sec_size, sgotplt, 0, closure);
     }
 
+  /* Only ELF files are supported for Xtensa.  Check here to avoid a segfault
+     when building uclibc, which runs "ld -b binary /dev/null".  */
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return ok;
+
   internal_relocs = retrieve_internal_relocs (abfd, sec, 
                                              link_info->keep_memory);
   if (internal_relocs == NULL