};
static struct bfd_elf_special_section const spu_elf_special_sections[] = {
+ { "._ea", 4, 0, SHT_PROGBITS, SHF_WRITE },
{ ".toe", 4, 0, SHT_NOBITS, SHF_ALLOC },
{ NULL, 0, 0, 0, 0 }
};
return _bfd_elf_new_section_hook (abfd, sec);
}
+/* Set up overlay info for executables. */
+
+static bfd_boolean
+spu_elf_object_p (bfd *abfd)
+{
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+ {
+ unsigned int i, num_ovl, num_buf;
+ Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
+ Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
+ Elf_Internal_Phdr *last_phdr = NULL;
+
+ for (num_buf = 0, num_ovl = 0, i = 0; i < ehdr->e_phnum; i++, phdr++)
+ if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_OVERLAY) != 0)
+ {
+ unsigned int j;
+
+ ++num_ovl;
+ if (last_phdr == NULL
+ || ((last_phdr->p_vaddr ^ phdr->p_vaddr) & 0x3ffff) != 0)
+ ++num_buf;
+ last_phdr = phdr;
+ for (j = 1; j < elf_numsections (abfd); j++)
+ {
+ Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[j];
+
+ if (ELF_IS_SECTION_IN_SEGMENT_MEMORY (shdr, phdr))
+ {
+ asection *sec = shdr->bfd_section;
+ spu_elf_section_data (sec)->u.o.ovl_index = num_ovl;
+ spu_elf_section_data (sec)->u.o.ovl_buf = num_buf;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
/* Specially mark defined symbols named _EAR_* with BSF_KEEP so that
strip --strip-unneeded will not remove them. */
unsigned int overlay_fixed;
/* Local store --auto-overlay should reserve for stack and heap. */
unsigned int reserved;
+ /* If reserved is not specified, stack analysis will calculate a value
+ for the stack. This parameter adjusts that value to allow for
+ negative sp access (the ABI says 2000 bytes below sp are valid,
+ and the overlay manager uses some of this area). */
+ int extra_stack_space;
/* Count of overlay stubs needed in non-overlay area. */
unsigned int non_ovly_stub;
{
locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
if (locsyms == NULL)
- {
- size_t symcount = symtab_hdr->sh_info;
-
- /* If we are reading symbols into the contents, then
- read the global syms too. This is done to cache
- syms for later stack analysis. */
- if ((unsigned char **) locsymsp == &symtab_hdr->contents)
- symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
- locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, 0,
- NULL, NULL, NULL);
- }
+ locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+ symtab_hdr->sh_info,
+ 0, NULL, NULL, NULL);
if (locsyms == NULL)
return FALSE;
*locsymsp = locsyms;
section needs a stub. */
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index
!= spu_elf_section_data (input_section->output_section)->u.o.ovl_index)
- return ovl_stub;
+ ret = ovl_stub;
/* If this insn isn't a branch then we are possibly taking the
address of a function and passing it out somehow. */
if (OVL_STUB_SIZE == 16)
val -= 12;
if (((dest | to | from) & 3) != 0
- || val + 0x20000 >= 0x40000)
+ || val + 0x40000 >= 0x80000)
{
htab->stub_err = 1;
return FALSE;
bfd_put_32 (sec->owner, BRSL + ((val << 5) & 0x007fff80) + 75,
sec->contents + sec->size);
- val = (dest & 0x3ffff) | (ovl << 14);
+ val = (dest & 0x3ffff) | (ovl << 18);
bfd_put_32 (sec->owner, val,
sec->contents + sec->size + 4);
}
&& (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0
|| htab->non_overlay_stubs))
{
- count_stub (htab, NULL, NULL, nonovl_stub, h, NULL);
+ return count_stub (htab, NULL, NULL, nonovl_stub, h, NULL);
}
return TRUE;
&& (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0
|| htab->non_overlay_stubs))
{
- build_stub (htab, NULL, NULL, nonovl_stub, h, NULL,
- h->root.u.def.value, sym_sec);
+ return build_stub (htab, NULL, NULL, nonovl_stub, h, NULL,
+ h->root.u.def.value, sym_sec);
}
return TRUE;
Elf_Internal_Shdr *symtab_hdr;
asection *isec;
Elf_Internal_Sym *local_syms = NULL;
- void *psyms;
if (ibfd->xvec != &bfd_elf32_spu_vec)
continue;
if (symtab_hdr->sh_info == 0)
continue;
- /* Arrange to read and keep global syms for later stack analysis. */
- psyms = &local_syms;
- if (htab->stack_analysis)
- psyms = &symtab_hdr->contents;
-
/* Walk over each section attached to the input bfd. */
for (isec = ibfd->sections; isec != NULL; isec = isec->next)
{
}
/* Determine the reloc target section. */
- if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, ibfd))
+ if (!get_sym_h (&h, &sym, &sym_sec, &local_syms, r_indx, ibfd))
goto error_ret_free_internal;
stub_type = needs_ovl_stub (h, sym, sym_sec, isec, irela,
/* Fill in all the stubs. */
process_stubs (info, TRUE);
+ if (!htab->stub_err)
+ elf_link_hash_traverse (&htab->elf, build_spuear_stubs, info);
- elf_link_hash_traverse (&htab->elf, build_spuear_stubs, info);
if (htab->stub_err)
- return FALSE;
+ {
+ (*_bfd_error_handler) (_("overlay stub relocation overflow"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
for (i = 0; i <= htab->num_overlays; i++)
{
htab->stub_sec[i]->rawsize = 0;
}
- if (htab->stub_err)
- {
- (*_bfd_error_handler) (_("overlay stub relocation overflow"));
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
-
htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size);
if (htab->ovtab->contents == NULL)
return FALSE;
unsigned int hi,
unsigned int overlay_fixed,
unsigned int reserved,
+ int extra_stack_space,
void (*spu_elf_load_ovl_mgr) (void),
FILE *(*spu_elf_open_overlay_script) (void),
void (*spu_elf_relink) (void))
htab->local_store = hi + 1 - lo;
htab->overlay_fixed = overlay_fixed;
htab->reserved = reserved;
+ htab->extra_stack_space = extra_stack_space;
htab->spu_elf_load_ovl_mgr = spu_elf_load_ovl_mgr;
htab->spu_elf_open_overlay_script = spu_elf_open_overlay_script;
htab->spu_elf_relink = spu_elf_relink;
return &sinfo->fun[i];
}
- if (++i < sinfo->num_fun)
- memmove (&sinfo->fun[i + 1], &sinfo->fun[i],
- (sinfo->num_fun - i) * sizeof (sinfo->fun[i]));
- else if (i >= sinfo->max_fun)
+ if (sinfo->num_fun >= sinfo->max_fun)
{
bfd_size_type amt = sizeof (struct spu_elf_stack_info);
bfd_size_type old = amt;
memset ((char *) sinfo + old, 0, amt - old);
sec_data->u.i.stack_info = sinfo;
}
+
+ if (++i < sinfo->num_fun)
+ memmove (&sinfo->fun[i + 1], &sinfo->fun[i],
+ (sinfo->num_fun - i) * sizeof (sinfo->fun[i]));
sinfo->fun[i].is_func = is_func;
sinfo->fun[i].global = global;
sinfo->fun[i].sec = sec;
{
Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Sym *syms;
void *psyms;
static bfd_boolean warned;
symtab_hdr = &elf_tdata (sec->owner)->symtab_hdr;
psyms = &symtab_hdr->contents;
- syms = *(Elf_Internal_Sym **) psyms;
irela = internal_relocs;
irelaend = irela + sec->reloc_count;
for (; irela < irelaend; irela++)
continue;
}
- syms = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (syms == NULL)
+ if (symtab_hdr->contents != NULL)
{
- syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, 0,
- NULL, NULL, NULL);
- symtab_hdr->contents = (void *) syms;
- if (syms == NULL)
- return FALSE;
+ /* Don't use cached symbols since the generic ELF linker
+ code only reads local symbols, and we need globals too. */
+ free (symtab_hdr->contents);
+ symtab_hdr->contents = NULL;
}
+ syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, 0,
+ NULL, NULL, NULL);
+ symtab_hdr->contents = (void *) syms;
+ if (syms == NULL)
+ return FALSE;
/* Select defined function symbols that are going to be output. */
psyms = bfd_malloc ((symcount + 1) * sizeof (*psyms));
return TRUE;
}
+/* If non-zero then unmark functions called from those within sections
+ that we need to unmark. Unfortunately this isn't reliable since the
+ call graph cannot know the destination of function pointer calls. */
+#define RECURSE_UNMARK 0
+
struct _uos_param {
asection *exclude_input_section;
asection *exclude_output_section;
|| fun->sec->output_section == uos_param->exclude_output_section)
excluded = 1;
- uos_param->clearing += excluded;
+ if (RECURSE_UNMARK)
+ uos_param->clearing += excluded;
- if (uos_param->clearing)
+ if (RECURSE_UNMARK ? uos_param->clearing : excluded)
{
fun->sec->linker_mark = 0;
if (fun->rodata)
if (!unmark_overlay_section (call->fun, info, param))
return FALSE;
- uos_param->clearing -= excluded;
+ if (RECURSE_UNMARK)
+ uos_param->clearing -= excluded;
return TRUE;
}
for (i = 1; i < bfd_count; ++i)
if (strcmp (bfd_arr[i - 1]->filename, bfd_arr[i]->filename) == 0)
{
- if (bfd_arr[i - 1]->my_archive && bfd_arr[i]->my_archive)
+ if (bfd_arr[i - 1]->my_archive == bfd_arr[i]->my_archive)
{
- if (bfd_arr[i - 1]->my_archive == bfd_arr[i]->my_archive)
+ if (bfd_arr[i - 1]->my_archive && bfd_arr[i]->my_archive)
info->callbacks->einfo (_("%s duplicated in %s\n"),
- bfd_arr[i - 1]->filename,
- bfd_arr[i - 1]->my_archive->filename);
- else
- info->callbacks->einfo (_("%s in both %s and %s\n"),
- bfd_arr[i - 1]->filename,
- bfd_arr[i - 1]->my_archive->filename,
+ bfd_arr[i]->filename,
bfd_arr[i]->my_archive->filename);
+ else
+ info->callbacks->einfo (_("%s duplicated\n"),
+ bfd_arr[i]->filename);
+ ok = FALSE;
}
- else if (bfd_arr[i - 1]->my_archive)
- info->callbacks->einfo (_("%s in %s and as an object\n"),
- bfd_arr[i - 1]->filename,
- bfd_arr[i - 1]->my_archive->filename);
- else if (bfd_arr[i]->my_archive)
- info->callbacks->einfo (_("%s in %s and as an object\n"),
- bfd_arr[i]->filename,
- bfd_arr[i]->my_archive->filename);
- else
- info->callbacks->einfo (_("%s duplicated\n"),
- bfd_arr[i]->filename);
- ok = FALSE;
}
if (!ok)
{
- /* FIXME: modify plain object files from foo.o to ./foo.o
- and emit EXCLUDE_FILE to handle the duplicates in
- archives. There is a pathological case we can't handle:
- We may have duplicate file names within a single archive. */
info->callbacks->einfo (_("sorry, no support for duplicate "
"object files in auto-overlay script\n"));
bfd_set_error (bfd_error_bad_value);
sum_stack_param.overall_stack = 0;
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE))
goto err_exit;
- htab->reserved = sum_stack_param.overall_stack;
+ htab->reserved = sum_stack_param.overall_stack + htab->extra_stack_space;
}
fixed_size += htab->reserved;
fixed_size += htab->non_ovly_stub * OVL_STUB_SIZE;
{
asection *sec = ovly_sections[2 * j];
- if (fprintf (script, " [%c]%s (%s)\n",
- sec->owner->filename[0],
- sec->owner->filename + 1,
+ if (fprintf (script, " %s%c%s (%s)\n",
+ (sec->owner->my_archive != NULL
+ ? sec->owner->my_archive->filename : ""),
+ info->path_separator,
+ sec->owner->filename,
sec->name) <= 0)
goto file_err;
if (sec->segment_mark)
{
struct function_info *call_fun = call->fun;
sec = call_fun->sec;
- if (fprintf (script, " [%c]%s (%s)\n",
- sec->owner->filename[0],
- sec->owner->filename + 1,
+ if (fprintf (script, " %s%c%s (%s)\n",
+ (sec->owner->my_archive != NULL
+ ? sec->owner->my_archive->filename : ""),
+ info->path_separator,
+ sec->owner->filename,
sec->name) <= 0)
goto file_err;
for (call = call_fun->call_list; call; call = call->next)
for (j = base; j < i; j++)
{
asection *sec = ovly_sections[2 * j + 1];
- if (sec != NULL && fprintf (script, " [%c]%s (%s)\n",
- sec->owner->filename[0],
- sec->owner->filename + 1,
- sec->name) <= 0)
+ if (sec != NULL
+ && fprintf (script, " %s%c%s (%s)\n",
+ (sec->owner->my_archive != NULL
+ ? sec->owner->my_archive->filename : ""),
+ info->path_separator,
+ sec->owner->filename,
+ sec->name) <= 0)
goto file_err;
sec = ovly_sections[2 * j];
{
struct function_info *call_fun = call->fun;
sec = call_fun->rodata;
- if (sec != NULL && fprintf (script, " [%c]%s (%s)\n",
- sec->owner->filename[0],
- sec->owner->filename + 1,
- sec->name) <= 0)
+ if (sec != NULL
+ && fprintf (script, " %s%c%s (%s)\n",
+ (sec->owner->my_archive != NULL
+ ? sec->owner->my_archive->filename : ""),
+ info->path_separator,
+ sec->owner->filename,
+ sec->name) <= 0)
goto file_err;
for (call = call_fun->call_list; call; call = call->next)
if (call->is_pasted)
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel, *relend;
struct spu_link_hash_table *htab;
+ asection *ea = bfd_get_section_by_name (output_bfd, "._ea");
int ret = TRUE;
bfd_boolean emit_these_relocs = FALSE;
+ bfd_boolean is_ea_sym;
bfd_boolean stubs;
htab = spu_hash_table (info);
{
int r_type;
reloc_howto_type *howto;
- unsigned long r_symndx;
+ unsigned int r_symndx;
Elf_Internal_Sym *sym;
asection *sec;
struct elf_link_hash_entry *h;
bfd_reloc_status_type r;
bfd_boolean unresolved_reloc;
bfd_boolean warned;
+ enum _stub_type stub_type;
r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info);
- if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64)
- {
- emit_these_relocs = TRUE;
- continue;
- }
-
howto = elf_howto_table + r_type;
unresolved_reloc = FALSE;
warned = FALSE;
}
else
{
- RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
- r_symndx, symtab_hdr, sym_hashes,
- h, sec, relocation,
- unresolved_reloc, warned);
+ if (sym_hashes == NULL)
+ return FALSE;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ relocation = 0;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ sec = h->root.u.def.section;
+ if (sec == NULL
+ || sec->output_section == NULL)
+ /* Set a flag that will be cleared later if we find a
+ relocation value for this symbol. output_section
+ is typically NULL for symbols satisfied by a shared
+ library. */
+ unresolved_reloc = TRUE;
+ else
+ relocation = (h->root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
+ }
+ else if (h->root.type == bfd_link_hash_undefweak)
+ ;
+ else if (info->unresolved_syms_in_objects == RM_IGNORE
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+ ;
+ else if (!info->relocatable
+ && !(r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64))
+ {
+ bfd_boolean err;
+ err = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
+ || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT);
+ if (!info->callbacks->undefined_symbol (info,
+ h->root.root.string,
+ input_bfd,
+ input_section,
+ rel->r_offset, err))
+ return FALSE;
+ warned = TRUE;
+ }
sym_name = h->root.root.string;
}
if (info->relocatable)
continue;
+ is_ea_sym = (ea != NULL
+ && sec != NULL
+ && sec->output_section == ea);
+
+ if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64)
+ {
+ if (is_ea_sym)
+ {
+ /* ._ea is a special section that isn't allocated in SPU
+ memory, but rather occupies space in PPU memory as
+ part of an embedded ELF image. If this reloc is
+ against a symbol defined in ._ea, then transform the
+ reloc into an equivalent one without a symbol
+ relative to the start of the ELF image. */
+ rel->r_addend += (relocation
+ - ea->vma
+ + elf_section_data (ea)->this_hdr.sh_offset);
+ rel->r_info = ELF32_R_INFO (0, r_type);
+ }
+ emit_these_relocs = TRUE;
+ continue;
+ }
+
+ if (is_ea_sym)
+ unresolved_reloc = TRUE;
+
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 (stubs)
+ if (stubs
+ && (stub_type = needs_ovl_stub (h, sym, sec, input_section, rel,
+ contents, info)) != no_stub)
{
- enum _stub_type stub_type;
-
- stub_type = needs_ovl_stub (h, sym, sec, input_section, rel,
- contents, info);
- if (stub_type != no_stub)
- {
- unsigned int ovl = 0;
- struct got_entry *g, **head;
+ unsigned int ovl = 0;
+ struct got_entry *g, **head;
- if (stub_type != nonovl_stub)
- ovl = (spu_elf_section_data (input_section->output_section)
- ->u.o.ovl_index);
+ if (stub_type != nonovl_stub)
+ ovl = (spu_elf_section_data (input_section->output_section)
+ ->u.o.ovl_index);
- if (h != NULL)
- head = &h->got.glist;
- else
- head = elf_local_got_ents (input_bfd) + r_symndx;
+ if (h != NULL)
+ head = &h->got.glist;
+ else
+ head = elf_local_got_ents (input_bfd) + r_symndx;
- for (g = *head; g != NULL; g = g->next)
- if (g->addend == addend && (g->ovl == ovl || g->ovl == 0))
- break;
- if (g == NULL)
- abort ();
+ for (g = *head; g != NULL; g = g->next)
+ if (g->addend == addend && (g->ovl == ovl || g->ovl == 0))
+ break;
+ if (g == NULL)
+ abort ();
- relocation = g->stub_addr;
- addend = 0;
- }
+ relocation = g->stub_addr;
+ addend = 0;
}
r = _bfd_final_link_relocate (howto,
if (ret
&& emit_these_relocs
- && !info->relocatable
&& !info->emitrelocations)
{
Elf_Internal_Rela *wrel;
#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 elf_backend_object_p spu_elf_object_p
#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