return elf_howto_table + spu_elf_bfd_to_reloc_type (code);
}
+static reloc_howto_type *
+spu_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++)
+ if (elf_howto_table[i].name != NULL
+ && strcasecmp (elf_howto_table[i].name, r_name) == 0)
+ return &elf_howto_table[i];
+
+ return NULL;
+}
+
/* Apply R_SPU_REL9 and R_SPU_REL9I relocs. */
static bfd_reloc_status_type
return TRUE;
}
-/* Build a name for an entry in the stub hash table. The input section
- id isn't really necessary but we add that in for consistency with
- ppc32 and ppc64 stub names. We can't use a local symbol name
- because ld -r might generate duplicate local symbols. */
+/* Build a name for an entry in the stub hash table. We can't use a
+ local symbol name because ld -r might generate duplicate local symbols. */
static char *
-spu_stub_name (const asection *input_sec,
- const asection *sym_sec,
+spu_stub_name (const asection *sym_sec,
const struct elf_link_hash_entry *h,
const Elf_Internal_Rela *rel)
{
if (h)
{
- len = 8 + 1 + strlen (h->root.root.string) + 1 + 8 + 1;
+ len = strlen (h->root.root.string) + 1 + 8 + 1;
stub_name = bfd_malloc (len);
if (stub_name == NULL)
return stub_name;
- sprintf (stub_name, "%08x.%s+%x",
- input_sec->id & 0xffffffff,
+ sprintf (stub_name, "%s+%x",
h->root.root.string,
(int) rel->r_addend & 0xffffffff);
len -= 8;
}
else
{
- len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
+ len = 8 + 1 + 8 + 1 + 8 + 1;
stub_name = bfd_malloc (len);
if (stub_name == NULL)
return stub_name;
- sprintf (stub_name, "%08x.%x:%x+%x",
- input_sec->id & 0xffffffff,
+ sprintf (stub_name, "%x:%x+%x",
sym_sec->id & 0xffffffff,
(int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
(int) rel->r_addend & 0xffffffff);
|| (insn[0] & 0xfc) == 0x10);
}
+/* Return TRUE if this reloc symbol should possibly go via an overlay stub. */
+
+static bfd_boolean
+needs_ovl_stub (const char *sym_name,
+ asection *sym_sec,
+ asection *input_section,
+ struct spu_link_hash_table *htab,
+ bfd_boolean is_branch)
+{
+ if (htab->num_overlays == 0)
+ return FALSE;
+
+ if (sym_sec == NULL
+ || sym_sec->output_section == NULL
+ || spu_elf_section_data (sym_sec->output_section) == NULL)
+ return FALSE;
+
+ /* setjmp always goes via an overlay stub, because then the return
+ and hence the longjmp goes via __ovly_return. That magically
+ makes setjmp/longjmp between overlays work. */
+ if (strncmp (sym_name, "setjmp", 6) == 0
+ && (sym_name[6] == '\0' || sym_name[6] == '@'))
+ return TRUE;
+
+ /* Usually, symbols in non-overlay sections don't need stubs. */
+ if (spu_elf_section_data (sym_sec->output_section)->ovl_index == 0
+ && !htab->non_overlay_stubs)
+ return FALSE;
+
+ /* A reference from some other section to a symbol in an overlay
+ section needs a stub. */
+ if (spu_elf_section_data (sym_sec->output_section)->ovl_index
+ != spu_elf_section_data (input_section->output_section)->ovl_index)
+ return TRUE;
+
+ /* If this insn isn't a branch then we are possibly taking the
+ address of a function and passing it out somehow. */
+ return !is_branch;
+}
+
struct stubarr {
+ struct bfd_hash_table *stub_hash_table;
struct spu_stub_hash_entry **sh;
unsigned int count;
+ int err;
};
+/* Called via elf_link_hash_traverse to allocate stubs for any _SPUEAR_
+ symbols. */
+
+static bfd_boolean
+allocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
+{
+ /* Symbols starting with _SPUEAR_ need a stub because they may be
+ invoked by the PPU. */
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->def_regular
+ && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0)
+ {
+ struct stubarr *stubs = inf;
+ static Elf_Internal_Rela zero_rel;
+ char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel);
+ struct spu_stub_hash_entry *sh;
+
+ if (stub_name == NULL)
+ {
+ stubs->err = 1;
+ return FALSE;
+ }
+
+ sh = (struct spu_stub_hash_entry *)
+ bfd_hash_lookup (stubs->stub_hash_table, stub_name, TRUE, FALSE);
+ if (sh == NULL)
+ {
+ free (stub_name);
+ return FALSE;
+ }
+
+ /* If this entry isn't new, we already have a stub. */
+ if (sh->target_section != NULL)
+ {
+ free (stub_name);
+ return TRUE;
+ }
+
+ sh->target_section = h->root.u.def.section;
+ sh->target_off = h->root.u.def.value;
+ stubs->count += 1;
+ }
+
+ return TRUE;
+}
+
/* Called via bfd_hash_traverse to set up pointers to all symbols
in the stub hash table. */
flagword flags;
htab->non_overlay_stubs = non_overlay_stubs;
+ stubs.stub_hash_table = &htab->stub_hash_table;
stubs.count = 0;
+ stubs.err = 0;
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
extern const bfd_target bfd_elf32_spu_vec;
asection *sym_sec;
Elf_Internal_Sym *sym;
struct elf_link_hash_entry *h;
+ const char *sym_name;
char *stub_name;
struct spu_stub_hash_entry *sh;
unsigned int sym_type;
/* We are only interested in function symbols. */
if (h != NULL)
- sym_type = h->type;
+ {
+ sym_type = h->type;
+ sym_name = h->root.root.string;
+ }
else
- sym_type = ELF_ST_TYPE (sym->st_info);
+ {
+ sym_type = ELF_ST_TYPE (sym->st_info);
+ sym_name = bfd_elf_sym_name (sym_sec->owner,
+ symtab_hdr,
+ sym,
+ sym_sec);
+ }
if (sym_type != STT_FUNC)
{
/* It's common for people to write assembly and forget
type to be correct to distinguish function pointer
initialisation from other pointer initialisation. */
if (insn_type == call)
- {
- const char *sym_name;
-
- if (h != NULL)
- sym_name = h->root.root.string;
- else
- sym_name = bfd_elf_sym_name (sym_sec->owner,
- symtab_hdr,
- sym,
- sym_sec);
-
- (*_bfd_error_handler) (_("warning: call to non-function"
- " symbol %s defined in %B"),
- sym_sec->owner, sym_name);
- }
+ (*_bfd_error_handler) (_("warning: call to non-function"
+ " symbol %s defined in %B"),
+ sym_sec->owner, sym_name);
else
continue;
}
- /* Usually, non-overlay sections don't need stubs. */
- if (!spu_elf_section_data (sym_sec->output_section)->ovl_index
- && !non_overlay_stubs)
+ if (!needs_ovl_stub (sym_name, sym_sec, section, htab,
+ insn_type != non_branch))
continue;
- /* We need a reference from some other section before
- we consider that a symbol might need an overlay stub. */
- if (spu_elf_section_data (sym_sec->output_section)->ovl_index
- == spu_elf_section_data (section->output_section)->ovl_index)
- {
- /* Or we need this to *not* be a branch. ie. We are
- possibly taking the address of a function and
- passing it out somehow. */
- if (insn_type != non_branch)
- continue;
- }
-
- stub_name = spu_stub_name (section, sym_sec, h, irela);
+ stub_name = spu_stub_name (sym_sec, h, irela);
if (stub_name == NULL)
goto error_ret_free_internal;
}
}
+ elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, &stubs);
+ if (stubs.err)
+ return FALSE;
+
*stub = NULL;
if (stubs.count == 0)
return TRUE;
size_t max;
os = (struct _ovl_stream *) stream;
- max = (char *) os->end - (char *) os->start;
+ max = (const char *) os->end - (const char *) os->start;
if ((ufile_ptr) offset >= max)
return 0;
if (count > max - offset)
count = max - offset;
- memcpy (buf, (char *) os->start + offset, count);
+ memcpy (buf, (const char *) os->start + offset, count);
return count;
}
size_t len1, len2;
char *name;
- len1 = sizeof ("ovl_call.") - 1;
+ len1 = sizeof ("00000000.ovl_call.") - 1;
len2 = strlen (ent->root.string);
name = bfd_malloc (len1 + len2 + 1);
if (name == NULL)
return FALSE;
- memcpy (name, ent->root.string, 9);
- memcpy (name + 9, "ovl_call.", len1);
- memcpy (name + 9 + len1, ent->root.string + 9, len2 - 9 + 1);
+ memcpy (name, "00000000.ovl_call.", len1);
+ memcpy (name + len1, ent->root.string, len2 + 1);
h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
if (h == NULL)
return FALSE;
struct spu_link_hash_table *htab;
bfd_boolean ret = TRUE;
- if (info->relocatable)
- return TRUE;
-
htab = spu_hash_table (info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd));
sym_name = h->root.root.string;
}
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (info->relocatable)
+ continue;
+
if (unresolved_reloc)
{
(*_bfd_error_handler)
/* If this symbol is in an overlay area, we may need to relocate
to the overlay stub. */
addend = rel->r_addend;
- if (sec != NULL
- && sec->output_section != NULL
- && sec->output_section->owner == output_bfd
- && (spu_elf_section_data (sec->output_section)->ovl_index != 0
- || htab->non_overlay_stubs)
- && !(sec == input_section
- && is_branch (contents + rel->r_offset)))
+ if (needs_ovl_stub (sym_name, sec, input_section, htab,
+ is_branch (contents + rel->r_offset)))
{
char *stub_name;
struct spu_stub_hash_entry *sh;
- stub_name = spu_stub_name (input_section, sec, h, rel);
+ stub_name = spu_stub_name (sec, h, rel);
if (stub_name == NULL)
return FALSE;
return ret;
}
+/* Adjust _SPUEAR_ syms to point at their overlay stubs. */
+
+static bfd_boolean
+spu_elf_output_symbol_hook (struct bfd_link_info *info,
+ const char *sym_name ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *sym,
+ asection *sym_sec ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h)
+{
+ struct spu_link_hash_table *htab = spu_hash_table (info);
+
+ if (!info->relocatable
+ && htab->num_overlays != 0
+ && h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->def_regular
+ && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0)
+ {
+ static Elf_Internal_Rela zero_rel;
+ char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel);
+ struct spu_stub_hash_entry *sh;
+
+ if (stub_name == NULL)
+ return FALSE;
+ sh = (struct spu_stub_hash_entry *)
+ bfd_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, FALSE);
+ free (stub_name);
+ if (sh == NULL)
+ return TRUE;
+ sym->st_shndx
+ = _bfd_elf_section_from_bfd_section (htab->stub->output_section->owner,
+ htab->stub->output_section);
+ sym->st_value = (htab->stub->output_section->vma
+ + htab->stub->output_offset
+ + sh->off);
+ }
+
+ return TRUE;
+}
+
static int spu_plugin = 0;
void
#define elf_backend_can_gc_sections 1
#define bfd_elf32_bfd_reloc_type_lookup spu_elf_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup
#define elf_info_to_howto spu_elf_info_to_howto
#define elf_backend_gc_mark_hook spu_elf_gc_mark_hook
#define elf_backend_relocate_section spu_elf_relocate_section
#define elf_backend_symbol_processing spu_elf_backend_symbol_processing
+#define elf_backend_link_output_symbol_hook spu_elf_output_symbol_hook
#define bfd_elf32_new_section_hook spu_elf_new_section_hook
#define bfd_elf32_bfd_link_hash_table_create spu_elf_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_free spu_elf_link_hash_table_free