{
struct elf_link_hash_table elf;
+ struct spu_elf_params *params;
+
/* Shortcuts to overlay sections. */
asection *ovtab;
asection *toe;
/* Count of overlay stubs needed in non-overlay area. */
unsigned int non_ovly_stub;
- /* Stash various callbacks for --auto-overlay. */
- void (*spu_elf_load_ovl_mgr) (void);
- FILE *(*spu_elf_open_overlay_script) (void);
- void (*spu_elf_relink) (void);
-
- /* Bit 0 set if --auto-overlay.
- Bit 1 set if --auto-relink.
- Bit 2 set if --overlay-rodata. */
- unsigned int auto_overlay : 3;
-#define AUTO_OVERLAY 1
-#define AUTO_RELINK 2
-#define OVERLAY_RODATA 4
-
- /* Set if we should emit symbols for stubs. */
- unsigned int emit_stub_syms:1;
-
- /* Set if we want stubs on calls out of overlay regions to
- non-overlay regions. */
- unsigned int non_overlay_stubs : 1;
-
/* Set on error. */
unsigned int stub_err : 1;
-
- /* Set if stack size analysis should be done. */
- unsigned int stack_analysis : 1;
-
- /* Set if __stack_* syms will be emitted. */
- unsigned int emit_stack_syms : 1;
};
/* Hijack the generic got fields for overlay stub accounting. */
#define spu_hash_table(p) \
((struct spu_link_hash_table *) ((p)->hash))
+struct call_info
+{
+ struct function_info *fun;
+ struct call_info *next;
+ unsigned int count;
+ unsigned int max_depth;
+ unsigned int is_tail : 1;
+ unsigned int is_pasted : 1;
+};
+
+struct function_info
+{
+ /* List of functions called. Also branches to hot/cold part of
+ function. */
+ struct call_info *call_list;
+ /* For hot/cold part of function, point to owner. */
+ struct function_info *start;
+ /* Symbol at start of function. */
+ union {
+ Elf_Internal_Sym *sym;
+ struct elf_link_hash_entry *h;
+ } u;
+ /* Function section. */
+ asection *sec;
+ asection *rodata;
+ /* Where last called from, and number of sections called from. */
+ asection *last_caller;
+ unsigned int call_count;
+ /* Address range of (this part of) function. */
+ bfd_vma lo, hi;
+ /* Stack usage. */
+ int stack;
+ /* Distance from root of call tree. Tail and hot/cold branches
+ count as one deeper. We aren't counting stack frames here. */
+ unsigned int depth;
+ /* Set if global symbol. */
+ unsigned int global : 1;
+ /* Set if known to be start of function (as distinct from a hunk
+ in hot/cold section. */
+ unsigned int is_func : 1;
+ /* Set if not a root node. */
+ unsigned int non_root : 1;
+ /* Flags used during call tree traversal. It's cheaper to replicate
+ the visit flags than have one which needs clearing after a traversal. */
+ unsigned int visit1 : 1;
+ unsigned int visit2 : 1;
+ unsigned int marking : 1;
+ unsigned int visit3 : 1;
+ unsigned int visit4 : 1;
+ unsigned int visit5 : 1;
+ unsigned int visit6 : 1;
+ unsigned int visit7 : 1;
+};
+
+struct spu_elf_stack_info
+{
+ int num_fun;
+ int max_fun;
+ /* Variable size array describing functions, one per contiguous
+ address range belonging to a function. */
+ struct function_info fun[1];
+};
+
/* Create a spu ELF linker hash table. */
static struct bfd_link_hash_table *
return &htab->elf.root;
}
+void
+spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params)
+{
+ struct spu_link_hash_table *htab = spu_hash_table (info);
+ htab->params = params;
+}
+
/* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP
to (hash, NULL) for global symbols, and (NULL, sym) for locals. Set
*SYMSECP to the symbol's section. *LOCSYMSP caches local syms. */
that the linker maps the sections to the right place in the output. */
bfd_boolean
-spu_elf_create_sections (struct bfd_link_info *info,
- int stack_analysis,
- int emit_stack_syms)
+spu_elf_create_sections (struct bfd_link_info *info)
{
bfd *ibfd;
- struct spu_link_hash_table *htab = spu_hash_table (info);
-
- /* Stash some options away where we can get at them later. */
- htab->stack_analysis = stack_analysis;
- htab->emit_stack_syms = emit_stack_syms;
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
if (bfd_get_section_by_name (ibfd, SPU_PTNOTE_SPUNAME) != NULL)
return ovl_index != 0;
}
-/* Support two sizes of overlay stubs, a slower more compact stub of two
- intructions, and a faster stub of four instructions. */
-#ifndef OVL_STUB_SIZE
-/* Default to faster. */
-#define OVL_STUB_SIZE 16
-/* #define OVL_STUB_SIZE 8 */
-#endif
#define BRSL 0x33000000
#define BR 0x32000000
#define NOP 0x40200000
/* True if INPUT_SECTION might need overlay stubs. */
static bfd_boolean
-maybe_needs_stubs (asection *input_section, bfd *output_bfd)
+maybe_needs_stubs (asection *input_section)
{
/* No stubs for debug sections and suchlike. */
if ((input_section->flags & SEC_ALLOC) == 0)
return FALSE;
/* No stubs for link-once sections that will be discarded. */
- if (input_section->output_section == NULL
- || input_section->output_section->owner != output_bfd)
+ if (input_section->output_section == bfd_abs_section_ptr)
return FALSE;
/* Don't create stubs for .eh_frame references. */
enum _stub_type ret = no_stub;
if (sym_sec == NULL
- || sym_sec->output_section == NULL
- || sym_sec->output_section->owner != info->output_bfd
+ || sym_sec->output_section == bfd_abs_section_ptr
|| spu_elf_section_data (sym_sec->output_section) == NULL)
return ret;
/* Usually, symbols in non-overlay sections don't need stubs. */
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0
- && !htab->non_overlay_stubs)
+ && !htab->params->non_overlay_stubs)
return ret;
if (h != NULL)
return TRUE;
}
+/* Support two sizes of overlay stubs, a slower more compact stub of two
+ intructions, and a faster stub of four instructions. */
+
+static unsigned int
+ovl_stub_size (enum _ovly_flavour ovly_flavour)
+{
+ return 8 << ovly_flavour;
+}
+
/* Two instruction overlay stubs look like:
brsl $75,__ovly_load
bfd_vma dest,
asection *dest_sec)
{
- unsigned int ovl;
+ unsigned int ovl, dest_ovl;
struct got_entry *g, **head;
asection *sec;
- bfd_vma addend, val, from, to;
+ bfd_vma addend, from, to;
ovl = 0;
if (stub_type != nonovl_stub)
to = (htab->ovly_load->root.u.def.value
+ htab->ovly_load->root.u.def.section->output_offset
+ htab->ovly_load->root.u.def.section->output_section->vma);
- val = to - from;
- if (OVL_STUB_SIZE == 16)
- val -= 12;
- if (((dest | to | from) & 3) != 0
- || val + 0x40000 >= 0x80000)
+
+ if (((dest | to | from) & 3) != 0)
{
htab->stub_err = 1;
return FALSE;
}
- ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index;
+ dest_ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index;
- if (OVL_STUB_SIZE == 16)
+ switch (htab->params->ovly_flavour)
{
- bfd_put_32 (sec->owner, ILA + ((ovl << 7) & 0x01ffff80) + 78,
+ case ovly_normal:
+ bfd_put_32 (sec->owner, ILA + ((dest_ovl << 7) & 0x01ffff80) + 78,
sec->contents + sec->size);
bfd_put_32 (sec->owner, LNOP,
sec->contents + sec->size + 4);
bfd_put_32 (sec->owner, ILA + ((dest << 7) & 0x01ffff80) + 79,
sec->contents + sec->size + 8);
- bfd_put_32 (sec->owner, BR + ((val << 5) & 0x007fff80),
+ bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80),
sec->contents + sec->size + 12);
- }
- else if (OVL_STUB_SIZE == 8)
- {
- bfd_put_32 (sec->owner, BRSL + ((val << 5) & 0x007fff80) + 75,
- sec->contents + sec->size);
+ break;
- val = (dest & 0x3ffff) | (ovl << 18);
- bfd_put_32 (sec->owner, val,
+ case ovly_compact:
+ bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75,
+ sec->contents + sec->size);
+ bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18),
sec->contents + sec->size + 4);
+ break;
+
+ default:
+ abort ();
}
- else
- abort ();
- sec->size += OVL_STUB_SIZE;
+ sec->size += ovl_stub_size (htab->params->ovly_flavour);
- if (htab->emit_stub_syms)
+ if (htab->params->emit_stub_syms)
{
size_t len;
char *name;
{
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = sec;
- h->root.u.def.value = sec->size - OVL_STUB_SIZE;
- h->size = OVL_STUB_SIZE;
+ h->size = ovl_stub_size (htab->params->ovly_flavour);
+ h->root.u.def.value = sec->size - h->size;
h->type = STT_FUNC;
h->ref_regular = 1;
h->def_regular = 1;
&& h->def_regular
&& strncmp (h->root.root.string, "_SPUEAR_", 8) == 0
&& (sym_sec = h->root.u.def.section) != NULL
- && sym_sec->output_section != NULL
- && sym_sec->output_section->owner == info->output_bfd
+ && sym_sec->output_section != bfd_abs_section_ptr
&& spu_elf_section_data (sym_sec->output_section) != NULL
&& (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0
- || htab->non_overlay_stubs))
+ || htab->params->non_overlay_stubs))
{
return count_stub (htab, NULL, NULL, nonovl_stub, h, NULL);
}
&& h->def_regular
&& strncmp (h->root.root.string, "_SPUEAR_", 8) == 0
&& (sym_sec = h->root.u.def.section) != NULL
- && sym_sec->output_section != NULL
- && sym_sec->output_section->owner == info->output_bfd
+ && sym_sec->output_section != bfd_abs_section_ptr
&& spu_elf_section_data (sym_sec->output_section) != NULL
&& (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0
- || htab->non_overlay_stubs))
+ || htab->params->non_overlay_stubs))
{
return build_stub (htab, NULL, NULL, nonovl_stub, h, NULL,
h->root.u.def.value, sym_sec);
|| isec->reloc_count == 0)
continue;
- if (!maybe_needs_stubs (isec, info->output_bfd))
+ if (!maybe_needs_stubs (isec))
continue;
/* Get the relocs. */
/* Allocate space for overlay call and return stubs. */
int
-spu_elf_size_stubs (struct bfd_link_info *info,
- void (*place_spu_section) (asection *, asection *,
- const char *),
- int non_overlay_stubs)
+spu_elf_size_stubs (struct bfd_link_info *info)
{
- struct spu_link_hash_table *htab = spu_hash_table (info);
+ struct spu_link_hash_table *htab;
bfd *ibfd;
bfd_size_type amt;
flagword flags;
unsigned int i;
asection *stub;
- htab->non_overlay_stubs = non_overlay_stubs;
if (!process_stubs (info, FALSE))
return 0;
+ htab = spu_hash_table (info);
elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, info);
if (htab->stub_err)
return 0;
stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags);
htab->stub_sec[0] = stub;
if (stub == NULL
- || !bfd_set_section_alignment (ibfd, stub, 3 + (OVL_STUB_SIZE > 8)))
+ || !bfd_set_section_alignment (ibfd, stub,
+ htab->params->ovly_flavour + 3))
return 0;
- stub->size = htab->stub_count[0] * OVL_STUB_SIZE;
- (*place_spu_section) (stub, NULL, ".text");
+ stub->size = htab->stub_count[0] * ovl_stub_size (htab->params->ovly_flavour);
+ (*htab->params->place_spu_section) (stub, NULL, ".text");
for (i = 0; i < htab->num_overlays; ++i)
{
stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags);
htab->stub_sec[ovl] = stub;
if (stub == NULL
- || !bfd_set_section_alignment (ibfd, stub, 3 + (OVL_STUB_SIZE > 8)))
+ || !bfd_set_section_alignment (ibfd, stub,
+ htab->params->ovly_flavour + 3))
return 0;
- stub->size = htab->stub_count[ovl] * OVL_STUB_SIZE;
- (*place_spu_section) (stub, osec, NULL);
+ stub->size = htab->stub_count[ovl] * ovl_stub_size (htab->params->ovly_flavour);
+ (*htab->params->place_spu_section) (stub, osec, NULL);
}
/* htab->ovtab consists of two arrays.
return 0;
htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4;
- (*place_spu_section) (htab->ovtab, NULL, ".data");
+ (*htab->params->place_spu_section) (htab->ovtab, NULL, ".data");
htab->toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC);
if (htab->toe == NULL
|| !bfd_set_section_alignment (ibfd, htab->toe, 4))
return 0;
htab->toe->size = 16;
- (*place_spu_section) (htab->toe, NULL, ".toe");
+ (*htab->params->place_spu_section) (htab->toe, NULL, ".toe");
return 2;
}
/* Fill in all stubs and the overlay tables. */
bfd_boolean
-spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms)
+spu_elf_build_stubs (struct bfd_link_info *info)
{
struct spu_link_hash_table *htab = spu_hash_table (info);
struct elf_link_hash_entry *h;
bfd *obfd;
unsigned int i;
- htab->emit_stub_syms = emit_syms;
if (htab->stub_count == NULL)
return TRUE;
LO .. HI inclusive, and stash some parameters for --auto-overlay. */
asection *
-spu_elf_check_vma (struct bfd_link_info *info,
- int auto_overlay,
- unsigned int lo,
- 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))
+spu_elf_check_vma (struct bfd_link_info *info)
{
struct elf_segment_map *m;
unsigned int i;
struct spu_link_hash_table *htab = spu_hash_table (info);
bfd *abfd = info->output_bfd;
+ bfd_vma hi = htab->params->local_store_hi;
+ bfd_vma lo = htab->params->local_store_lo;
- if (auto_overlay & AUTO_OVERLAY)
- htab->auto_overlay = auto_overlay;
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;
for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
if (m->p_type == PT_LOAD)
return m->sections[i];
/* No need for overlays if it all fits. */
- htab->auto_overlay = 0;
+ htab->params->auto_overlay = 0;
return NULL;
}
return *s1 < *s2 ? -1 : 1;
}
-struct call_info
-{
- struct function_info *fun;
- struct call_info *next;
- unsigned int count;
- unsigned int max_depth;
- unsigned int is_tail : 1;
- unsigned int is_pasted : 1;
-};
-
-struct function_info
-{
- /* List of functions called. Also branches to hot/cold part of
- function. */
- struct call_info *call_list;
- /* For hot/cold part of function, point to owner. */
- struct function_info *start;
- /* Symbol at start of function. */
- union {
- Elf_Internal_Sym *sym;
- struct elf_link_hash_entry *h;
- } u;
- /* Function section. */
- asection *sec;
- asection *rodata;
- /* Where last called from, and number of sections called from. */
- asection *last_caller;
- unsigned int call_count;
- /* Address range of (this part of) function. */
- bfd_vma lo, hi;
- /* Stack usage. */
- int stack;
- /* Distance from root of call tree. Tail and hot/cold branches
- count as one deeper. We aren't counting stack frames here. */
- unsigned int depth;
- /* Set if global symbol. */
- unsigned int global : 1;
- /* Set if known to be start of function (as distinct from a hunk
- in hot/cold section. */
- unsigned int is_func : 1;
- /* Set if not a root node. */
- unsigned int non_root : 1;
- /* Flags used during call tree traversal. It's cheaper to replicate
- the visit flags than have one which needs clearing after a traversal. */
- unsigned int visit1 : 1;
- unsigned int visit2 : 1;
- unsigned int marking : 1;
- unsigned int visit3 : 1;
- unsigned int visit4 : 1;
- unsigned int visit5 : 1;
- unsigned int visit6 : 1;
- unsigned int visit7 : 1;
-};
-
-struct spu_elf_stack_info
-{
- int num_fun;
- int max_fun;
- /* Variable size array describing functions, one per contiguous
- address range belonging to a function. */
- struct function_info fun[1];
-};
-
/* Allocate a struct spu_elf_stack_info with MAX_FUN struct function_info
entries for section SEC. */
overlay stub sections. */
static bfd_boolean
-interesting_section (asection *s, bfd *obfd)
+interesting_section (asection *s)
{
- return (s->output_section != NULL
- && s->output_section->owner == obfd
+ return (s->output_section != bfd_abs_section_ptr
&& ((s->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_IN_MEMORY))
== (SEC_ALLOC | SEC_LOAD | SEC_CODE))
&& s->size != 0);
void *psyms;
static bfd_boolean warned;
- if (!interesting_section (sec, info->output_bfd)
+ if (!interesting_section (sec)
|| sec->reloc_count == 0)
return TRUE;
&& r_type != R_SPU_ADDR16)
{
reject = TRUE;
- if (!(call_tree && spu_hash_table (info)->auto_overlay))
+ if (!(call_tree && spu_hash_table (info)->params->auto_overlay))
continue;
}
return FALSE;
if (sym_sec == NULL
- || sym_sec->output_section == NULL
- || sym_sec->output_section->owner != info->output_bfd)
+ || sym_sec->output_section == bfd_abs_section_ptr)
continue;
is_call = FALSE;
else
{
reject = TRUE;
- if (!(call_tree && spu_hash_table (info)->auto_overlay)
+ if (!(call_tree && spu_hash_table (info)->params->auto_overlay)
|| is_hint (insn))
continue;
}
{
if (!gaps)
for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
- if (interesting_section (sec, info->output_bfd))
+ if (interesting_section (sec))
{
gaps = TRUE;
break;
asection *s;
*p = s = bfd_section_from_elf_index (ibfd, sy->st_shndx);
- if (s != NULL && interesting_section (s, info->output_bfd))
+ if (s != NULL && interesting_section (s))
*psy++ = sy;
}
symcount = psy - psyms;
}
for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
- if (interesting_section (sec, info->output_bfd))
+ if (interesting_section (sec))
gaps |= check_function_ranges (sec, info);
}
gaps = FALSE;
for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
- if (interesting_section (sec, info->output_bfd))
+ if (interesting_section (sec))
gaps |= check_function_ranges (sec, info);
if (!gaps)
continue;
the range of such functions to the beginning of the
next symbol of interest. */
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
- if (interesting_section (sec, info->output_bfd))
+ if (interesting_section (sec))
{
struct _spu_elf_section_data *sec_data;
struct spu_elf_stack_info *sinfo;
}
else if (call->fun->marking)
{
- if (!spu_hash_table (info)->auto_overlay)
+ if (!spu_hash_table (info)->params->auto_overlay)
{
const char *f1 = func_name (fun);
const char *f2 = func_name (call->fun);
/* Transfer call info from hot/cold section part of function
to main entry. */
- if (!spu_hash_table (info)->auto_overlay
+ if (!spu_hash_table (info)->params->auto_overlay
&& !for_each_node (transfer_calls, info, 0, FALSE))
return FALSE;
this flag to differentiate the two overlay section types. */
fun->sec->flags |= SEC_CODE;
- if (spu_hash_table (info)->auto_overlay & OVERLAY_RODATA)
+ if (spu_hash_table (info)->params->auto_overlay & OVERLAY_RODATA)
{
char *name = NULL;
unsigned int i, lib_count;
struct _cl_param collect_lib_param;
struct function_info dummy_caller;
+ struct spu_link_hash_table *htab;
memset (&dummy_caller, 0, sizeof (dummy_caller));
lib_count = 0;
if (lib_count > 1)
qsort (lib_sections, lib_count, 2 * sizeof (*lib_sections), sort_lib);
+ htab = spu_hash_table (info);
for (i = 0; i < lib_count; i++)
{
unsigned int tmp, stub_size;
if (p->fun == call->fun)
break;
if (!p)
- stub_size += OVL_STUB_SIZE;
+ stub_size += ovl_stub_size (htab->params->ovly_flavour);
}
}
if (tmp + stub_size < lib_size)
while ((p = *pp) != NULL)
if (!p->fun->sec->linker_mark)
{
- lib_size += OVL_STUB_SIZE;
+ lib_size += ovl_stub_size (htab->params->ovly_flavour);
*pp = p->next;
free (p);
}
sum_stack_param->overall_stack = cum_stack;
htab = spu_hash_table (info);
- if (htab->auto_overlay)
+ if (htab->params->auto_overlay)
return TRUE;
f1 = func_name (fun);
/* Handle --auto-overlay. */
-static void spu_elf_auto_overlay (struct bfd_link_info *, void (*) (void))
+static void spu_elf_auto_overlay (struct bfd_link_info *)
ATTRIBUTE_NORETURN;
static void
-spu_elf_auto_overlay (struct bfd_link_info *info,
- void (*spu_elf_load_ovl_mgr) (void))
+spu_elf_auto_overlay (struct bfd_link_info *info)
{
bfd *ibfd;
bfd **bfd_arr;
{
/* If no user overlay manager, spu_elf_load_ovl_mgr will add our
builtin version to .text, and will adjust .text size. */
- asection *text = bfd_get_section_by_name (info->output_bfd, ".text");
- if (text != NULL)
- fixed_size -= text->size;
- spu_elf_load_ovl_mgr ();
- text = bfd_get_section_by_name (info->output_bfd, ".text");
- if (text != NULL)
- fixed_size += text->size;
+ fixed_size += (*htab->params->spu_elf_load_ovl_mgr) ();
}
/* Mark overlay sections, and find max overlay section size. */
htab->reserved = sum_stack_param.overall_stack + htab->extra_stack_space;
}
fixed_size += htab->reserved;
- fixed_size += htab->non_ovly_stub * OVL_STUB_SIZE;
+ fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params->ovly_flavour);
if (fixed_size + mos_param.max_overlay_size <= htab->local_store)
{
/* Guess number of overlays. Assuming overlay buffer is on
goto err_exit;
count = (size_t) (ovly_p - ovly_sections) / 2;
- script = htab->spu_elf_open_overlay_script ();
+ script = (*htab->params->spu_elf_open_overlay_script) ();
if (fprintf (script, "SECTIONS\n{\n OVERLAY :\n {\n") <= 0)
goto file_err;
{
asection *sec;
unsigned int tmp;
- unsigned int stub_size;
+ unsigned int num_stubs;
struct call_info *call, *pasty;
struct _spu_elf_section_data *sec_data;
struct spu_elf_stack_info *sinfo;
}
/* Calculate call stub size. */
- stub_size = 0;
+ num_stubs = 0;
for (call = dummy_caller.call_list; call; call = call->next)
{
unsigned int k;
- stub_size += OVL_STUB_SIZE;
+ ++num_stubs;
/* If the call is within this overlay, we won't need a
stub. */
for (k = base; k < i + 1; k++)
if (call->fun->sec == ovly_sections[2 * k])
{
- stub_size -= OVL_STUB_SIZE;
+ --num_stubs;
break;
}
}
- if (tmp + stub_size > overlay_size)
+ if (tmp + num_stubs * ovl_stub_size (htab->params->ovly_flavour)
+ > overlay_size)
break;
size = tmp;
if (fclose (script) != 0)
goto file_err;
- if (htab->auto_overlay & AUTO_RELINK)
- htab->spu_elf_relink ();
+ if (htab->params->auto_overlay & AUTO_RELINK)
+ (*htab->params->spu_elf_relink) ();
xexit (0);
/* Provide an estimate of total stack required. */
static bfd_boolean
-spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
+spu_elf_stack_analysis (struct bfd_link_info *info)
{
+ struct spu_link_hash_table *htab;
struct _sum_stack_param sum_stack_param;
if (!discover_functions (info))
if (!build_call_tree (info))
return FALSE;
+ htab = spu_hash_table (info);
info->callbacks->info (_("Stack size for call graph root nodes.\n"));
info->callbacks->minfo (_("\nStack size for functions. "
"Annotations: '*' max stack, 't' tail call\n"));
- sum_stack_param.emit_stack_syms = emit_stack_syms;
+ sum_stack_param.emit_stack_syms = htab->params->emit_stack_syms;
sum_stack_param.overall_stack = 0;
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE))
return FALSE;
{
struct spu_link_hash_table *htab = spu_hash_table (info);
- if (htab->auto_overlay)
- spu_elf_auto_overlay (info, htab->spu_elf_load_ovl_mgr);
+ if (htab->params->auto_overlay)
+ spu_elf_auto_overlay (info);
- if (htab->stack_analysis
- && !spu_elf_stack_analysis (info, htab->emit_stack_syms))
+ if (htab->params->stack_analysis
+ && !spu_elf_stack_analysis (info))
info->callbacks->einfo ("%X%P: stack analysis error: %E\n");
return bfd_elf_final_link (output_bfd, info);
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");
+ asection *ea;
int ret = TRUE;
bfd_boolean emit_these_relocs = FALSE;
bfd_boolean is_ea_sym;
htab = spu_hash_table (info);
stubs = (htab->stub_sec != NULL
- && maybe_needs_stubs (input_section, output_bfd));
+ && maybe_needs_stubs (input_section));
+ ea = bfd_get_section_by_name (output_bfd, "._ea");
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd));
#include "ldctor.h"
#include "elf32-spu.h"
-/* Non-zero if no overlay processing should be done. */
-static int no_overlays = 0;
+static void spu_place_special_section (asection *, asection *, const char *);
+static bfd_size_type spu_elf_load_ovl_mgr (void);
+static FILE *spu_elf_open_overlay_script (void);
+static void spu_elf_relink (void);
-/* Non-zero if we want stubs on all calls out of overlay regions. */
-static int non_overlay_stubs = 0;
-
-/* Whether to emit symbols for stubs. */
-static int emit_stub_syms = 0;
-
-/* Non-zero to perform stack space analysis. */
-static int stack_analysis = 0;
-
-/* Whether to emit symbols with stack requirements for each function. */
-static int emit_stack_syms = 0;
-
-/* Range of valid addresses for loadable sections. */
-static bfd_vma local_store_lo = 0;
-static bfd_vma local_store_hi = 0x3ffff;
-
-/* Control --auto-overlay feature. */
-static int auto_overlay = 0;
+static struct spu_elf_params params =
+{
+ &spu_place_special_section,
+ &spu_elf_load_ovl_mgr,
+ &spu_elf_open_overlay_script,
+ &spu_elf_relink,
+ 0, ovly_normal, 0, 0, 0, 0,
+ 0, 0x3ffff,
+ 0, 0, 2000
+};
+
static char *auto_overlay_file = 0;
-static unsigned int auto_overlay_fixed = 0;
-static unsigned int auto_overlay_reserved = 0;
-static int extra_stack_space = 2000;
int my_argc;
char **my_argv;
static void
spu_after_open (void)
{
- if (is_spu_target ()
- && !link_info.relocatable
- && link_info.input_bfds != NULL
- && !spu_elf_create_sections (&link_info,
- stack_analysis, emit_stack_syms))
- einfo ("%X%P: can not create note section: %E\n");
+ if (is_spu_target ())
+ {
+ /* Pass params to backend. */
+ if ((params.auto_overlay & AUTO_OVERLAY) == 0)
+ params.auto_overlay = 0;
+ params.emit_stub_syms |= link_info.emitrelocations;
+ spu_elf_setup (&link_info, ¶ms);
+
+ if (!link_info.relocatable
+ && link_info.input_bfds != NULL
+ && !spu_elf_create_sections (&link_info))
+ einfo ("%X%P: can not create note section: %E\n");
+ }
gld${EMULATION_NAME}_after_open ();
}
{
lang_output_section_statement_type *os;
- os = lang_output_section_find (o != NULL ? o->name : output_name);
+ if (o != NULL)
+ output_name = o->name;
+ os = lang_output_section_find (output_name);
if (os == NULL)
gld${EMULATION_NAME}_place_orphan (s, output_name, 0);
else if (o != NULL && os->children.head != NULL)
s->output_section->size += s->size;
}
-/* Load built-in overlay manager, and tweak overlay section alignment. */
+/* Load built-in overlay manager. */
-static void
+static bfd_size_type
spu_elf_load_ovl_mgr (void)
{
- lang_output_section_statement_type *os;
struct elf_link_hash_entry *h;
+ bfd_size_type total = 0;
h = elf_link_hash_lookup (elf_hash_table (&link_info),
"__ovly_load", FALSE, FALSE, FALSE);
for (in = ovl_is->the_bfd->sections; in != NULL; in = in->next)
if ((in->flags & (SEC_ALLOC | SEC_LOAD))
== (SEC_ALLOC | SEC_LOAD))
- spu_place_special_section (in, NULL, ".text");
+ {
+ total += in->size;
+ spu_place_special_section (in, NULL, ".text");
+ }
}
}
-
- /* Ensure alignment of overlay sections is sufficient. */
- for (os = &lang_output_section_statement.head->output_section_statement;
- os != NULL;
- os = os->next)
- if (os->bfd_section != NULL
- && spu_elf_section_data (os->bfd_section) != NULL
- && spu_elf_section_data (os->bfd_section)->u.o.ovl_index != 0)
- {
- if (os->bfd_section->alignment_power < 4)
- os->bfd_section->alignment_power = 4;
-
- /* Also ensure size rounds up. */
- os->block_value = 16;
- }
+ return total;
}
/* Go find if we need to do anything special for overlays. */
{
if (is_spu_target ()
&& !link_info.relocatable
- && !no_overlays)
+ && params.ovly_flavour != ovly_none)
{
/* Size the sections. This is premature, but we need to know the
rough layout so that overlays can be found. */
if (spu_elf_find_overlays (&link_info))
{
int ret;
+ lang_output_section_statement_type *os;
- if (auto_overlay != 0)
+ if (params.auto_overlay != 0)
{
einfo ("%P: --auto-overlay ignored with user overlay script\n");
- auto_overlay = 0;
+ params.auto_overlay = 0;
}
- ret = spu_elf_size_stubs (&link_info,
- spu_place_special_section,
- non_overlay_stubs);
+ /* Ensure alignment of overlay sections is sufficient. */
+ for (os = &lang_output_section_statement.head->output_section_statement;
+ os != NULL;
+ os = os->next)
+ if (os->bfd_section != NULL
+ && spu_elf_section_data (os->bfd_section) != NULL
+ && spu_elf_section_data (os->bfd_section)->u.o.ovl_index != 0)
+ {
+ if (os->bfd_section->alignment_power < 4)
+ os->bfd_section->alignment_power = 4;
+
+ /* Also ensure size rounds up. */
+ os->block_value = 16;
+ }
+
+ ret = spu_elf_size_stubs (&link_info);
if (ret == 0)
einfo ("%X%P: can not size overlay stubs: %E\n");
else if (ret == 2)
if (is_spu_target ())
{
- if (local_store_lo < local_store_hi)
+ if (params.local_store_lo < params.local_store_hi)
{
asection *s;
- s = spu_elf_check_vma (&link_info, auto_overlay,
- local_store_lo, local_store_hi,
- auto_overlay_fixed, auto_overlay_reserved,
- extra_stack_space,
- spu_elf_load_ovl_mgr,
- spu_elf_open_overlay_script,
- spu_elf_relink);
- if (s != NULL && !auto_overlay)
+ s = spu_elf_check_vma (&link_info);
+ if (s != NULL && !params.auto_overlay)
einfo ("%X%P: %A exceeds local store range\n", s);
}
- else if (auto_overlay)
+ else if (params.auto_overlay)
einfo ("%P: --auto-overlay ignored with zero local store range\n");
- if (!spu_elf_build_stubs (&link_info,
- emit_stub_syms || link_info.emitrelocations))
+ if (!spu_elf_build_stubs (&link_info))
einfo ("%F%P: can not build overlay stubs: %E\n");
}
break;
case OPTION_SPU_NO_OVERLAYS:
- no_overlays = 1;
+ params.ovly_flavour = ovly_none;
break;
case OPTION_SPU_STUB_SYMS:
- emit_stub_syms = 1;
+ params.emit_stub_syms = 1;
break;
case OPTION_SPU_NON_OVERLAY_STUBS:
- non_overlay_stubs = 1;
+ params.non_overlay_stubs = 1;
break;
case OPTION_SPU_LOCAL_STORE:
{
char *end;
- local_store_lo = strtoul (optarg, &end, 0);
+ params.local_store_lo = strtoul (optarg, &end, 0);
if (*end == '\'':'\'')
{
- local_store_hi = strtoul (end + 1, &end, 0);
+ params.local_store_hi = strtoul (end + 1, &end, 0);
if (*end == 0)
break;
}
break;
case OPTION_SPU_STACK_ANALYSIS:
- stack_analysis = 1;
+ params.stack_analysis = 1;
break;
case OPTION_SPU_STACK_SYMS:
- emit_stack_syms = 1;
+ params.emit_stack_syms = 1;
break;
case OPTION_SPU_AUTO_OVERLAY:
- auto_overlay |= 1;
+ params.auto_overlay |= 1;
if (optarg != NULL)
{
auto_overlay_file = optarg;
/* Fall thru */
case OPTION_SPU_AUTO_RELINK:
- auto_overlay |= 2;
+ params.auto_overlay |= 2;
break;
case OPTION_SPU_OVERLAY_RODATA:
- auto_overlay |= 4;
+ params.auto_overlay |= 4;
break;
case OPTION_SPU_FIXED_SPACE:
{
char *end;
- auto_overlay_fixed = strtoul (optarg, &end, 0);
+ params.auto_overlay_fixed = strtoul (optarg, &end, 0);
if (*end != 0)
einfo (_("%P%F: invalid --fixed-space value `%s'\''\n"), optarg);
}
case OPTION_SPU_RESERVED_SPACE:
{
char *end;
- auto_overlay_reserved = strtoul (optarg, &end, 0);
+ params.auto_overlay_reserved = strtoul (optarg, &end, 0);
if (*end != 0)
einfo (_("%P%F: invalid --reserved-space value `%s'\''\n"), optarg);
}
case OPTION_SPU_EXTRA_STACK:
{
char *end;
- extra_stack_space = strtol (optarg, &end, 0);
+ params.extra_stack_space = strtol (optarg, &end, 0);
if (*end != 0)
einfo (_("%P%F: invalid --extra-stack-space value `%s'\''\n"), optarg);
}
break;
case OPTION_SPU_NO_AUTO_OVERLAY:
- auto_overlay = 0;
+ params.auto_overlay = 0;
if (optarg != NULL)
{
struct tflist *tf;