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>
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);
}
+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. */
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));
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;
}
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))
/* 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. */
break;
}
irel->r_offset -= removed_bytes;
- irel++;
}
}
{
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