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. */
static int
find_function_stack_adjust (asection *sec, bfd_vma offset)
{
- int unrecog;
int reg[128];
memset (reg, 0, sizeof (reg));
- for (unrecog = 0; offset + 4 <= sec->size && unrecog < 32; offset += 4)
+ for ( ; offset + 4 <= sec->size; offset += 4)
{
unsigned char buf[4];
int rt, ra;
if (rt == 1 /* sp */)
{
- if (imm > 0)
+ if (reg[rt] > 0)
break;
return reg[rt];
}
reg[rt] = reg[ra] + reg[rb];
if (rt == 1)
- return reg[rt];
+ {
+ if (reg[rt] > 0)
+ break;
+ return reg[rt];
+ }
}
else if ((buf[0] & 0xfc) == 0x40 /* il, ilh, ilhu, ila */)
{
if (buf[0] == 0x40 /* il */)
{
if ((buf[1] & 0x80) == 0)
- goto unknown_insn;
+ continue;
imm = (imm ^ 0x8000) - 0x8000;
}
else if ((buf[1] & 0x80) == 0 /* ilhu */)
reg[rt] = reg[ra] | imm;
continue;
}
- else if ((buf[0] == 0x33 && imm == 1 /* brsl .+4 */)
- || (buf[0] == 0x08 && (buf[1] & 0xe0) == 0 /* sf */))
+ else if (buf[0] == 0x32 && (buf[1] & 0x80) != 0 /* fsmbi */)
+ {
+ reg[rt] = ( ((imm & 0x8000) ? 0xff000000 : 0)
+ | ((imm & 0x4000) ? 0x00ff0000 : 0)
+ | ((imm & 0x2000) ? 0x0000ff00 : 0)
+ | ((imm & 0x1000) ? 0x000000ff : 0));
+ continue;
+ }
+ else if (buf[0] == 0x16 /* andbi */)
+ {
+ imm >>= 7;
+ imm &= 0xff;
+ imm |= imm << 8;
+ imm |= imm << 16;
+ reg[rt] = reg[ra] & imm;
+ continue;
+ }
+ else if (buf[0] == 0x33 && imm == 1 /* brsl .+4 */)
{
- /* Used in pic reg load. Say rt is trashed. */
+ /* Used in pic reg load. Say rt is trashed. Won't be used
+ in stack adjust, but we need to continue past this branch. */
reg[rt] = 0;
continue;
}
else if (is_branch (buf) || is_indirect_branch (buf))
/* If we hit a branch then we must be out of the prologue. */
break;
- unknown_insn:
- ++unrecog;
}
return 0;
return TRUE;
}
+/* Check that we actually visited all nodes in remove_cycles. If we
+ didn't, then there is some cycle in the call graph not attached to
+ any root node. Arbitrarily choose a node in the cycle as a new
+ root and break the cycle. */
+
+static bfd_boolean
+mark_detached_root (struct function_info *fun,
+ struct bfd_link_info *info,
+ void *param)
+{
+ if (fun->visit2)
+ return TRUE;
+ fun->non_root = FALSE;
+ *(unsigned int *) param = 0;
+ return remove_cycles (fun, info, param);
+}
+
/* Populate call_list for each function. */
static bfd_boolean
/* Remove cycles from the call graph. We start from the root node(s)
so that we break cycles in a reasonable place. */
depth = 0;
- return for_each_node (remove_cycles, info, &depth, TRUE);
+ if (!for_each_node (remove_cycles, info, &depth, TRUE))
+ return FALSE;
+
+ return for_each_node (mark_detached_root, info, &depth, FALSE);
}
/* qsort predicate to sort calls by max_depth then count. */
if (delta != 0)
return delta;
- return c1 - c2;
+ return (char *) c1 - (char *) c2;
}
struct _mos_param {
fun->visit4 = TRUE;
if (!fun->sec->linker_mark)
{
+ unsigned int size;
+
fun->sec->linker_mark = 1;
fun->sec->gc_mark = 1;
fun->sec->segment_mark = 0;
be!), and SEC_CODE is clear on rodata sections. We use
this flag to differentiate the two overlay section types. */
fun->sec->flags |= SEC_CODE;
+
if (spu_hash_table (info)->auto_overlay & OVERLAY_RODATA)
{
char *name = NULL;
- unsigned int size;
/* Find the rodata section corresponding to this function's
text section. */
}
free (name);
}
- size = fun->sec->size;
- if (fun->rodata)
- size += fun->rodata->size;
- if (mos_param->max_overlay_size < size)
- mos_param->max_overlay_size = size;
}
+ size = fun->sec->size;
+ if (fun->rodata)
+ size += fun->rodata->size;
+ if (mos_param->max_overlay_size < size)
+ mos_param->max_overlay_size = size;
}
for (count = 0, call = fun->call_list; call != NULL; call = call->next)
}
if (fixed_size + mos_param.max_overlay_size > htab->local_store)
- info->callbacks->einfo (_("non-overlay plus maximum overlay size "
- "of 0x%x exceeds local store\n"),
- fixed_size + mos_param.max_overlay_size);
+ info->callbacks->einfo (_("non-overlay size of 0x%v plus maximum overlay "
+ "size of 0x%v exceeds local store\n"),
+ (bfd_vma) fixed_size,
+ (bfd_vma) mos_param.max_overlay_size);
/* Now see if we should put some functions in the non-overlay area. */
- if (fixed_size < htab->overlay_fixed
- && htab->overlay_fixed + mos_param.max_overlay_size < htab->local_store)
+ else if (fixed_size < htab->overlay_fixed)
{
- unsigned int lib_size = htab->overlay_fixed - fixed_size;
+ unsigned int max_fixed, lib_size;
+
+ max_fixed = htab->local_store - mos_param.max_overlay_size;
+ if (max_fixed > htab->overlay_fixed)
+ max_fixed = htab->overlay_fixed;
+ lib_size = max_fixed - fixed_size;
lib_size = auto_ovl_lib_functions (info, lib_size);
if (lib_size == (unsigned int) -1)
goto err_exit;
- fixed_size = htab->overlay_fixed - lib_size;
+ fixed_size = max_fixed - lib_size;
}
/* Build an array of sections, suitably sorted to place into
that need to be emitted. */
static unsigned int
-spu_elf_count_relocs (asection *sec, Elf_Internal_Rela *relocs)
+spu_elf_count_relocs (struct bfd_link_info *info, asection *sec)
{
+ Elf_Internal_Rela *relocs;
unsigned int count = 0;
- Elf_Internal_Rela *relend = relocs + sec->reloc_count;
- for (; relocs < relend; relocs++)
+ relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+ info->keep_memory);
+ if (relocs != NULL)
{
- int r_type = ELF32_R_TYPE (relocs->r_info);
- if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64)
- ++count;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend = relocs + sec->reloc_count;
+
+ for (rel = relocs; rel < relend; rel++)
+ {
+ int r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64)
+ ++count;
+ }
+
+ if (elf_section_data (sec)->relocs != relocs)
+ free (relocs);
}
return count;
}
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;
}
static int
spu_elf_additional_program_headers (bfd *abfd, struct bfd_link_info *info)
{
- struct spu_link_hash_table *htab = spu_hash_table (info);
- int extra = htab->num_overlays;
+ int extra = 0;
asection *sec;
+ if (info != NULL)
+ {
+ struct spu_link_hash_table *htab = spu_hash_table (info);
+ extra = htab->num_overlays;
+ }
+
if (extra)
++extra;