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
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include <stdarg.h>
#include <strings.h>
static bfd_boolean is_reloc_sym_weak (bfd *, Elf_Internal_Rela *);
static bfd_boolean pcrel_reloc_fits (xtensa_opcode, int, bfd_vma, bfd_vma);
static bfd_boolean xtensa_is_property_section (asection *);
+static bfd_boolean xtensa_is_insntable_section (asection *);
static bfd_boolean xtensa_is_littable_section (asection *);
+static bfd_boolean xtensa_is_proptable_section (asection *);
static int internal_reloc_compare (const void *, const void *);
static int internal_reloc_matches (const void *, const void *);
extern asection *xtensa_get_property_section (asection *, const char *);
property_table_entry *blocks;
int blk, block_count;
bfd_size_type num_records;
- Elf_Internal_Rela *internal_relocs;
- bfd_vma section_addr;
+ Elf_Internal_Rela *internal_relocs, *irel, *rel_end;
+ bfd_vma section_addr, off;
flagword predef_flags;
- bfd_size_type table_entry_size;
+ bfd_size_type table_entry_size, section_limit;
if (!section
|| !(section->flags & SEC_ALLOC)
else
section_addr = section->vma;
- /* If the file has not yet been relocated, process the relocations
- and sort out the table entries that apply to the specified section. */
internal_relocs = retrieve_internal_relocs (abfd, table_section, TRUE);
if (internal_relocs && !table_section->reloc_done)
{
- unsigned i;
-
- for (i = 0; i < table_section->reloc_count; i++)
- {
- Elf_Internal_Rela *rel = &internal_relocs[i];
- unsigned long r_symndx;
+ qsort (internal_relocs, table_section->reloc_count,
+ sizeof (Elf_Internal_Rela), internal_reloc_compare);
+ irel = internal_relocs;
+ }
+ else
+ irel = NULL;
- if (ELF32_R_TYPE (rel->r_info) == R_XTENSA_NONE)
- continue;
+ section_limit = bfd_get_section_limit (abfd, section);
+ rel_end = internal_relocs + table_section->reloc_count;
- BFD_ASSERT (ELF32_R_TYPE (rel->r_info) == R_XTENSA_32);
- r_symndx = ELF32_R_SYM (rel->r_info);
+ for (off = 0; off < table_size; off += table_entry_size)
+ {
+ bfd_vma address = bfd_get_32 (abfd, table_data + off);
- if (get_elf_r_symndx_section (abfd, r_symndx) == section)
- {
- bfd_vma sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
- BFD_ASSERT (sym_off == 0);
- blocks[block_count].address =
- (section_addr + sym_off + rel->r_addend
- + bfd_get_32 (abfd, table_data + rel->r_offset));
- blocks[block_count].size =
- bfd_get_32 (abfd, table_data + rel->r_offset + 4);
- if (predef_flags)
- blocks[block_count].flags = predef_flags;
- else
- blocks[block_count].flags =
- bfd_get_32 (abfd, table_data + rel->r_offset + 8);
- block_count++;
- }
+ /* Skip any relocations before the current offset. This should help
+ avoid confusion caused by unexpected relocations for the preceding
+ table entry. */
+ while (irel &&
+ (irel->r_offset < off
+ || (irel->r_offset == off
+ && ELF32_R_TYPE (irel->r_info) == R_XTENSA_NONE)))
+ {
+ irel += 1;
+ if (irel >= rel_end)
+ irel = 0;
}
- }
- else
- {
- /* The file has already been relocated and the addresses are
- already in the table. */
- bfd_vma off;
- bfd_size_type section_limit = bfd_get_section_limit (abfd, section);
- for (off = 0; off < table_size; off += table_entry_size)
+ if (irel && irel->r_offset == off)
{
- bfd_vma address = bfd_get_32 (abfd, table_data + off);
+ bfd_vma sym_off;
+ unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
+ BFD_ASSERT (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32);
- if (address >= section_addr
- && address < section_addr + section_limit)
- {
- blocks[block_count].address = address;
- blocks[block_count].size =
- bfd_get_32 (abfd, table_data + off + 4);
- if (predef_flags)
- blocks[block_count].flags = predef_flags;
- else
- blocks[block_count].flags =
- bfd_get_32 (abfd, table_data + off + 8);
- block_count++;
- }
+ if (get_elf_r_symndx_section (abfd, r_symndx) != section)
+ continue;
+
+ sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
+ BFD_ASSERT (sym_off == 0);
+ address += (section_addr + sym_off + irel->r_addend);
}
+ else
+ {
+ if (address < section_addr
+ || address >= section_addr + section_limit)
+ continue;
+ }
+
+ blocks[block_count].address = address;
+ blocks[block_count].size = bfd_get_32 (abfd, table_data + off + 4);
+ if (predef_flags)
+ blocks[block_count].flags = predef_flags;
+ else
+ blocks[block_count].flags = bfd_get_32 (abfd, table_data + off + 8);
+ block_count++;
}
release_contents (table_section, table_data);
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;
}
+static void
+elf_xtensa_make_sym_local (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ if (info->shared)
+ {
+ if (h->plt.refcount > 0)
+ {
+ /* For shared objects, there's no need for PLT entries for local
+ symbols (use RELATIVE relocs instead of JMP_SLOT relocs). */
+ if (h->got.refcount < 0)
+ h->got.refcount = 0;
+ h->got.refcount += h->plt.refcount;
+ h->plt.refcount = 0;
+ }
+ }
+ else
+ {
+ /* Don't need any dynamic relocations at all. */
+ h->plt.refcount = 0;
+ h->got.refcount = 0;
+ }
+}
+
+
+static void
+elf_xtensa_hide_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_boolean force_local)
+{
+ /* For a shared link, move the plt refcount to the got refcount to leave
+ space for RELATIVE relocs. */
+ elf_xtensa_make_sym_local (info, h);
+
+ _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+}
+
+
/* Return the section that should be marked against GC for a given
relocation. */
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
+ /* Property sections are marked "KEEP" in the linker scripts, but they
+ should not cause other sections to be marked. (This approach relies
+ on elf_xtensa_discard_info to remove property table entries that
+ describe discarded sections. Alternatively, it might be more
+ efficient to avoid using "KEEP" in the linker scripts and instead use
+ the gc_mark_extra_sections hook to mark only the property sections
+ that describe marked sections. That alternative does not work well
+ with the current property table sections, which do not correspond
+ one-to-one with the sections they describe, but that should be fixed
+ someday.) */
+ if (xtensa_is_property_section (sec))
+ return NULL;
+
if (h != NULL)
switch (ELF32_R_TYPE (rel->r_info))
{
is_dynamic = elf_xtensa_dynamic_symbol_p (h, info);
if (! is_dynamic)
- {
- if (info->shared)
- {
- /* For shared objects, there's no need for PLT entries for local
- symbols (use RELATIVE relocs instead of JMP_SLOT relocs). */
- if (h->plt.refcount > 0)
- {
- if (h->got.refcount < 0)
- h->got.refcount = 0;
- h->got.refcount += h->plt.refcount;
- h->plt.refcount = 0;
- }
- }
- else
- {
- /* Don't need any dynamic relocations at all. */
- h->plt.refcount = 0;
- h->got.refcount = 0;
- }
- }
+ elf_xtensa_make_sym_local (info, h);
if (h->plt.refcount > 0)
htab->srelplt->size += (h->plt.refcount * sizeof (Elf32_External_Rela));
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)
/* 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. */
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:
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;
}
bfd_byte *contents;
bfd_vma section_size;
bfd_vma offset, actual_offset;
- size_t removed_bytes = 0;
-
- section_size = sec->size;
- if (section_size == 0 || section_size % 8 != 0)
- return FALSE;
+ bfd_size_type removed_bytes = 0;
+ bfd_size_type entry_size;
if (sec->output_section
&& bfd_is_abs_section (sec->output_section))
return FALSE;
+ if (xtensa_is_proptable_section (sec))
+ entry_size = 12;
+ else
+ entry_size = 8;
+
+ section_size = sec->size;
+ if (section_size == 0 || section_size % entry_size != 0)
+ return FALSE;
+
contents = retrieve_contents (abfd, sec, info->keep_memory);
if (!contents)
return FALSE;
return FALSE;
}
+ /* Sort the relocations. They should already be in order when
+ relaxation is enabled, but it might not be. */
+ qsort (cookie->rels, sec->reloc_count, sizeof (Elf_Internal_Rela),
+ internal_reloc_compare);
+
cookie->rel = cookie->rels;
cookie->relend = cookie->rels + sec->reloc_count;
- for (offset = 0; offset < section_size; offset += 8)
+ for (offset = 0; offset < section_size; offset += entry_size)
{
actual_offset = offset - removed_bytes;
if (ELF32_R_TYPE (cookie->rel->r_info) != R_XTENSA_NONE)
{
/* Shift the contents up. */
- if (offset + 8 < section_size)
+ if (offset + entry_size < section_size)
memmove (&contents[actual_offset],
- &contents[actual_offset+8],
- section_size - offset - 8);
- removed_bytes += 8;
+ &contents[actual_offset + entry_size],
+ section_size - offset - entry_size);
+ removed_bytes += entry_size;
}
/* Remove this relocation. */
}
-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);
}
}
-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 *
bfd_vma src_offset;
unsigned src_type; /* Relocation type. */
- bfd *target_abfd;
asection *target_sec;
bfd_vma target_offset;
bfd_boolean translated;
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)
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;
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;
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)
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);
the_entry++;
}
- if (the_entry->flags & XTENSA_PROP_INSN_NO_TRANSFORM)
+ if (the_entry->flags & XTENSA_PROP_NO_TRANSFORM)
/* NO_REORDER is OK */
continue;
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))
bad_alignment = FALSE;
break;
}
+ if (new_action->do_action)
+ removed_bytes += new_action->removed_bytes;
}
if (!bad_alignment)
{
/* 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))
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];
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. */
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);
/* 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);
{
Elf_Internal_Rela *internal_relocs;
bfd_byte *contents;
- unsigned i, nexti;
+ unsigned i;
bfd_boolean ok = TRUE;
bfd_boolean is_full_prop_section;
size_t last_zfill_target_offset = 0;
asection *last_zfill_target_sec = NULL;
bfd_size_type sec_size;
+ bfd_size_type entry_size;
sec_size = bfd_get_section_limit (abfd, sec);
internal_relocs = retrieve_internal_relocs (abfd, sec,
goto error_return;
}
- is_full_prop_section =
- ( CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME)
- || CONST_STRNEQ (sec->name, ".gnu.linkonce.prop."));
+ is_full_prop_section = xtensa_is_proptable_section (sec);
+ if (is_full_prop_section)
+ entry_size = 12;
+ else
+ entry_size = 8;
if (internal_relocs)
{
size_p = &contents[irel->r_offset + 4];
flags_p = NULL;
if (is_full_prop_section)
- {
- flags_p = &contents[irel->r_offset + 8];
- BFD_ASSERT (irel->r_offset + 12 <= sec_size);
- }
- else
- BFD_ASSERT (irel->r_offset + 8 <= sec_size);
+ flags_p = &contents[irel->r_offset + 8];
+ BFD_ASSERT (irel->r_offset + entry_size <= sec_size);
target_sec = r_reloc_get_section (&val.r_rel);
target_relax_info = get_xtensa_relax_info (target_sec);
|| 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)
{
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)
{
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);
}
reclaim the space in the output section, so we do this twice. */
if (internal_relocs && (!link_info->relocatable
- || strcmp (sec->name, XTENSA_LIT_SEC_NAME) == 0))
+ || xtensa_is_littable_section (sec)))
{
Elf_Internal_Rela *last_irel = NULL;
+ Elf_Internal_Rela *irel, *next_rel, *rel_end;
int removed_bytes = 0;
- bfd_vma offset, last_irel_offset;
+ bfd_vma offset;
bfd_vma section_size;
- bfd_size_type entry_size;
flagword predef_flags;
- if (is_full_prop_section)
- entry_size = 12;
- else
- entry_size = 8;
-
predef_flags = xtensa_get_property_predef_flags (sec);
- /* Walk over memory and irels at the same time.
+ /* Walk over memory and relocations at the same time.
This REQUIRES that the internal_relocs be sorted by offset. */
qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
internal_reloc_compare);
- nexti = 0; /* Index into internal_relocs. */
pin_internal_relocs (sec, internal_relocs);
pin_contents (sec, contents);
- last_irel_offset = (bfd_vma) -1;
+ next_rel = internal_relocs;
+ rel_end = internal_relocs + sec->reloc_count;
+
section_size = sec->size;
BFD_ASSERT (section_size % entry_size == 0);
for (offset = 0; offset < section_size; offset += entry_size)
{
- Elf_Internal_Rela *irel, *next_irel;
+ Elf_Internal_Rela *offset_rel, *extra_rel;
bfd_vma bytes_to_remove, size, actual_offset;
- bfd_boolean remove_this_irel;
+ bfd_boolean remove_this_rel;
flagword flags;
- irel = NULL;
- next_irel = NULL;
-
- /* Find the next two relocations (if there are that many left),
- skipping over any R_XTENSA_NONE relocs. On entry, "nexti" is
- the starting reloc index. After these two loops, "i"
- is the index of the first non-NONE reloc past that starting
- index, and "nexti" is the index for the next non-NONE reloc
- after "i". */
+ /* Find the first relocation for the entry at the current offset.
+ Adjust the offsets of any extra relocations for the previous
+ entry. */
+ offset_rel = NULL;
+ if (next_rel)
+ {
+ for (irel = next_rel; irel < rel_end; irel++)
+ {
+ if ((irel->r_offset == offset
+ && ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE)
+ || irel->r_offset > offset)
+ {
+ offset_rel = irel;
+ break;
+ }
+ irel->r_offset -= removed_bytes;
+ }
+ }
- for (i = nexti; i < sec->reloc_count; i++)
+ /* Find the next relocation (if there are any left). */
+ extra_rel = NULL;
+ if (offset_rel)
{
- if (ELF32_R_TYPE (internal_relocs[i].r_info) != R_XTENSA_NONE)
+ for (irel = offset_rel + 1; irel < rel_end; irel++)
{
- irel = &internal_relocs[i];
- break;
+ if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE)
+ {
+ extra_rel = irel;
+ break;
+ }
}
- internal_relocs[i].r_offset -= removed_bytes;
}
- for (nexti = i + 1; nexti < sec->reloc_count; nexti++)
+ /* Check if there are relocations on the current entry. There
+ should usually be a relocation on the offset field. If there
+ are relocations on the size or flags, then we can't optimize
+ this entry. Also, find the next relocation to examine on the
+ next iteration. */
+ if (offset_rel)
{
- if (ELF32_R_TYPE (internal_relocs[nexti].r_info)
- != R_XTENSA_NONE)
+ if (offset_rel->r_offset >= offset + entry_size)
{
- next_irel = &internal_relocs[nexti];
- break;
+ next_rel = offset_rel;
+ /* There are no relocations on the current entry, but we
+ might still be able to remove it if the size is zero. */
+ offset_rel = NULL;
+ }
+ else if (offset_rel->r_offset > offset
+ || (extra_rel
+ && extra_rel->r_offset < offset + entry_size))
+ {
+ /* There is a relocation on the size or flags, so we can't
+ do anything with this entry. Continue with the next. */
+ next_rel = offset_rel;
+ continue;
+ }
+ else
+ {
+ BFD_ASSERT (offset_rel->r_offset == offset);
+ offset_rel->r_offset -= removed_bytes;
+ next_rel = offset_rel + 1;
}
- internal_relocs[nexti].r_offset -= removed_bytes;
}
+ else
+ next_rel = NULL;
- remove_this_irel = FALSE;
+ remove_this_rel = FALSE;
bytes_to_remove = 0;
actual_offset = offset - removed_bytes;
size = bfd_get_32 (abfd, &contents[actual_offset + 4]);
else
flags = predef_flags;
- /* Check that the irels are sorted by offset,
- with only one per address. */
- BFD_ASSERT (!irel || (int) irel->r_offset > (int) last_irel_offset);
- BFD_ASSERT (!next_irel || next_irel->r_offset > irel->r_offset);
-
- /* Make sure there aren't relocs on the size or flag fields. */
- if ((irel && irel->r_offset == offset + 4)
- || (is_full_prop_section
- && irel && irel->r_offset == offset + 8))
- {
- irel->r_offset -= removed_bytes;
- last_irel_offset = irel->r_offset;
- }
- else if (next_irel && (next_irel->r_offset == offset + 4
- || (is_full_prop_section
- && next_irel->r_offset == offset + 8)))
- {
- nexti += 1;
- irel->r_offset -= removed_bytes;
- next_irel->r_offset -= removed_bytes;
- last_irel_offset = next_irel->r_offset;
- }
- else if (size == 0 && (flags & XTENSA_PROP_ALIGN) == 0
- && (flags & XTENSA_PROP_UNREACHABLE) == 0)
+ if (size == 0
+ && (flags & XTENSA_PROP_ALIGN) == 0
+ && (flags & XTENSA_PROP_UNREACHABLE) == 0)
{
/* Always remove entries with zero size and no alignment. */
bytes_to_remove = entry_size;
- if (irel && irel->r_offset == offset)
- {
- remove_this_irel = TRUE;
-
- irel->r_offset -= removed_bytes;
- last_irel_offset = irel->r_offset;
- }
+ if (offset_rel)
+ remove_this_rel = TRUE;
}
- else if (irel && irel->r_offset == offset)
+ else if (offset_rel
+ && ELF32_R_TYPE (offset_rel->r_info) == R_XTENSA_32)
{
- if (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32)
+ if (last_irel)
{
- if (last_irel)
+ flagword old_flags;
+ bfd_vma old_size =
+ bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]);
+ bfd_vma old_address =
+ (last_irel->r_addend
+ + bfd_get_32 (abfd, &contents[last_irel->r_offset]));
+ bfd_vma new_address =
+ (offset_rel->r_addend
+ + bfd_get_32 (abfd, &contents[actual_offset]));
+ if (is_full_prop_section)
+ old_flags = bfd_get_32
+ (abfd, &contents[last_irel->r_offset + 8]);
+ else
+ old_flags = predef_flags;
+
+ if ((ELF32_R_SYM (offset_rel->r_info)
+ == ELF32_R_SYM (last_irel->r_info))
+ && old_address + old_size == new_address
+ && old_flags == flags
+ && (old_flags & XTENSA_PROP_INSN_BRANCH_TARGET) == 0
+ && (old_flags & XTENSA_PROP_INSN_LOOP_TARGET) == 0)
{
- flagword old_flags;
- bfd_vma old_size =
- bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]);
- bfd_vma old_address =
- (last_irel->r_addend
- + bfd_get_32 (abfd, &contents[last_irel->r_offset]));
- bfd_vma new_address =
- (irel->r_addend
- + bfd_get_32 (abfd, &contents[actual_offset]));
- if (is_full_prop_section)
- old_flags = bfd_get_32
- (abfd, &contents[last_irel->r_offset + 8]);
- else
- old_flags = predef_flags;
-
- if ((ELF32_R_SYM (irel->r_info)
- == ELF32_R_SYM (last_irel->r_info))
- && old_address + old_size == new_address
- && old_flags == flags
- && (old_flags & XTENSA_PROP_INSN_BRANCH_TARGET) == 0
- && (old_flags & XTENSA_PROP_INSN_LOOP_TARGET) == 0)
- {
- /* Fix the old size. */
- bfd_put_32 (abfd, old_size + size,
- &contents[last_irel->r_offset + 4]);
- bytes_to_remove = entry_size;
- remove_this_irel = TRUE;
- }
- else
- last_irel = irel;
+ /* Fix the old size. */
+ bfd_put_32 (abfd, old_size + size,
+ &contents[last_irel->r_offset + 4]);
+ bytes_to_remove = entry_size;
+ remove_this_rel = TRUE;
}
else
- last_irel = irel;
+ last_irel = offset_rel;
}
-
- irel->r_offset -= removed_bytes;
- last_irel_offset = irel->r_offset;
+ else
+ last_irel = offset_rel;
}
- if (remove_this_irel)
+ if (remove_this_rel)
{
- irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
- irel->r_offset -= bytes_to_remove;
+ offset_rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+ /* In case this is the last entry, move the relocation offset
+ to the previous entry, if there is one. */
+ if (offset_rel->r_offset >= bytes_to_remove)
+ offset_rel->r_offset -= bytes_to_remove;
+ else
+ offset_rel->r_offset = 0;
}
if (bytes_to_remove != 0)
if (removed_bytes)
{
+ /* Fix up any extra relocations on the last entry. */
+ for (irel = next_rel; irel < rel_end; irel++)
+ irel->r_offset -= removed_bytes;
+
/* Clear the removed bytes. */
memset (&contents[section_size - removed_bytes], 0, removed_bytes);
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);
}
}
|| 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);
}
}
}
-static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
-
static bfd_boolean
xtensa_is_property_section (asection *sec)
{
- if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME)
- || CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME)
- || CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME))
+ if (xtensa_is_insntable_section (sec)
+ || xtensa_is_littable_section (sec)
+ || xtensa_is_proptable_section (sec))
return TRUE;
- if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0
- && (CONST_STRNEQ (&sec->name[linkonce_len], "x.")
- || CONST_STRNEQ (&sec->name[linkonce_len], "p.")
- || CONST_STRNEQ (&sec->name[linkonce_len], "prop.")))
+ return FALSE;
+}
+
+
+static bfd_boolean
+xtensa_is_insntable_section (asection *sec)
+{
+ if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME)
+ || CONST_STRNEQ (sec->name, ".gnu.linkonce.x."))
return TRUE;
return FALSE;
static bfd_boolean
xtensa_is_littable_section (asection *sec)
{
- if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME))
+ if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME)
+ || CONST_STRNEQ (sec->name, ".gnu.linkonce.p."))
return TRUE;
- if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0
- && sec->name[linkonce_len] == 'p'
- && sec->name[linkonce_len + 1] == '.')
+ return FALSE;
+}
+
+
+static bfd_boolean
+xtensa_is_proptable_section (asection *sec)
+{
+ if (CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME)
+ || CONST_STRNEQ (sec->name, ".gnu.linkonce.prop."))
return TRUE;
return FALSE;
}
+static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+
asection *
xtensa_get_property_section (asection *sec, const char *base_name)
{
flagword
xtensa_get_property_predef_flags (asection *sec)
{
- if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME)
- || CONST_STRNEQ (sec->name, ".gnu.linkonce.x."))
+ 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;
(*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
#define elf_backend_gc_sweep_hook elf_xtensa_gc_sweep_hook
#define elf_backend_grok_prstatus elf_xtensa_grok_prstatus
#define elf_backend_grok_psinfo elf_xtensa_grok_psinfo
+#define elf_backend_hide_symbol elf_xtensa_hide_symbol
#define elf_backend_object_p elf_xtensa_object_p
#define elf_backend_reloc_type_class elf_xtensa_reloc_type_class
#define elf_backend_relocate_section elf_xtensa_relocate_section