* elf32-spu.g (struct spu_elf_params, enum _ovly_flavour): New.
	(spu_elf_setup): Declare.
	(spu_elf_create_sections, spu_elf_size_stubs): Update prototype.
	(spu_elf_build_stubs, spu_elf_check_vma): Likewise.
	* elf32-spu.c (struct spu_link_hash_table): Add "params". Remove
	various other fields now in "params".  Adjust code throughout.
	(struct call_info, struct function_info): Move earlier in file.
	(struct spu_elf_stack_info): Likewise.
	(spu_elf_setup): New function.
	(spu_elf_create_sections): Remove args other than "info".
	(spu_elf_size_stubs, spu_elf_build_stubs, spu_elf_check_vma): Likewise.
	(maybe_needs_stubs): Remove "output_bfd" arg.  Adjust all calls.
	(interesting_section): Similarly with "obfd" arg.
	(needs_ovl_stub): Adjust output_section test.
	(allocate_spuear_stubs): Likewise.
	(OVL_STUB_SIZE): Don't define.
	(ovl_stub_size): New function, use in place of OVL_STUB_SIZE.
	(build_stub): Test params->ovly_flavour rather than OVL_STUB_SIZE.
	(spu_elf_auto_overlay): Remove args other than "info".  Make use
	of size returned from spu_elf_load_ovl_mgr.
	(spu_elf_stack_analysis): Remove args other than "info".
	(spu_elf_relocate_section): Tidy setting of "ea".
ld/
	* emultempl/spuelf.em (params): New var, used instead of various others.
	Adjust use throughout file.
	(spu_after_open): Call spu_elf_setup.
	(spu_place_special_section): Tidy.
	(spu_elf_load_ovl_mgr): Return total size of sections loaded.  Move
	code setting overlay section alignment to..
	(spu_before_allocation): ..here.
This commit is contained in:
Alan Modra 2008-12-10 06:32:52 +00:00
parent b0c4170911
commit 64615358cc
5 changed files with 342 additions and 313 deletions

View file

@ -1,3 +1,28 @@
2008-12-10 Alan Modra <amodra@bigpond.net.au>
* elf32-spu.g (struct spu_elf_params, enum _ovly_flavour): New.
(spu_elf_setup): Declare.
(spu_elf_create_sections, spu_elf_size_stubs): Update prototype.
(spu_elf_build_stubs, spu_elf_check_vma): Likewise.
* elf32-spu.c (struct spu_link_hash_table): Add "params". Remove
various other fields now in "params". Adjust code throughout.
(struct call_info, struct function_info): Move earlier in file.
(struct spu_elf_stack_info): Likewise.
(spu_elf_setup): New function.
(spu_elf_create_sections): Remove args other than "info".
(spu_elf_size_stubs, spu_elf_build_stubs, spu_elf_check_vma): Likewise.
(maybe_needs_stubs): Remove "output_bfd" arg. Adjust all calls.
(interesting_section): Similarly with "obfd" arg.
(needs_ovl_stub): Adjust output_section test.
(allocate_spuear_stubs): Likewise.
(OVL_STUB_SIZE): Don't define.
(ovl_stub_size): New function, use in place of OVL_STUB_SIZE.
(build_stub): Test params->ovly_flavour rather than OVL_STUB_SIZE.
(spu_elf_auto_overlay): Remove args other than "info". Make use
of size returned from spu_elf_load_ovl_mgr.
(spu_elf_stack_analysis): Remove args other than "info".
(spu_elf_relocate_section): Tidy setting of "ea".
2008-12-10 Alan Modra <amodra@bigpond.net.au>
* elf32-spu.c (find_function_stack_adjust): Don't limit number

View file

@ -297,6 +297,8 @@ struct spu_link_hash_table
{
struct elf_link_hash_table elf;
struct spu_elf_params *params;
/* Shortcuts to overlay sections. */
asection *ovtab;
asection *toe;
@ -333,34 +335,8 @@ struct spu_link_hash_table
/* 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. */
@ -376,6 +352,69 @@ struct got_entry
#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 *
@ -405,6 +444,13 @@ spu_elf_link_hash_table_create (bfd *abfd)
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. */
@ -479,16 +525,9 @@ get_sym_h (struct elf_link_hash_entry **hp,
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)
@ -626,13 +665,6 @@ spu_elf_find_overlays (struct bfd_link_info *info)
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
@ -684,15 +716,14 @@ is_hint (const unsigned char *insn)
/* 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. */
@ -729,8 +760,7 @@ needs_ovl_stub (struct elf_link_hash_entry *h,
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;
@ -750,7 +780,7 @@ needs_ovl_stub (struct elf_link_hash_entry *h,
/* 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)
@ -911,6 +941,15 @@ count_stub (struct spu_link_hash_table *htab,
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
@ -936,10 +975,10 @@ build_stub (struct spu_link_hash_table *htab,
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)
@ -973,42 +1012,40 @@ build_stub (struct spu_link_hash_table *htab,
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,
break;
case ovly_compact:
bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75,
sec->contents + sec->size);
val = (dest & 0x3ffff) | (ovl << 18);
bfd_put_32 (sec->owner, val,
bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18),
sec->contents + sec->size + 4);
}
else
abort ();
sec->size += OVL_STUB_SIZE;
break;
if (htab->emit_stub_syms)
default:
abort ();
}
sec->size += ovl_stub_size (htab->params->ovly_flavour);
if (htab->params->emit_stub_syms)
{
size_t len;
char *name;
@ -1046,8 +1083,8 @@ build_stub (struct spu_link_hash_table *htab,
{
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;
@ -1077,11 +1114,10 @@ allocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
&& 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);
}
@ -1103,11 +1139,10 @@ build_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
&& 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);
@ -1149,7 +1184,7 @@ process_stubs (struct bfd_link_info *info, bfd_boolean build)
|| isec->reloc_count == 0)
continue;
if (!maybe_needs_stubs (isec, info->output_bfd))
if (!maybe_needs_stubs (isec))
continue;
/* Get the relocs. */
@ -1248,22 +1283,19 @@ process_stubs (struct bfd_link_info *info, bfd_boolean build)
/* 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;
@ -1282,10 +1314,11 @@ spu_elf_size_stubs (struct bfd_link_info *info,
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)
{
@ -1294,10 +1327,11 @@ spu_elf_size_stubs (struct bfd_link_info *info,
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.
@ -1321,14 +1355,14 @@ spu_elf_size_stubs (struct bfd_link_info *info,
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;
}
@ -1423,7 +1457,7 @@ define_ovtab_symbol (struct spu_link_hash_table *htab, const char *name)
/* 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;
@ -1432,7 +1466,6 @@ spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms)
bfd *obfd;
unsigned int i;
htab->emit_stub_syms = emit_syms;
if (htab->stub_count == NULL)
return TRUE;
@ -1552,31 +1585,16 @@ spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms)
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)
@ -1588,7 +1606,7 @@ spu_elf_check_vma (struct bfd_link_info *info,
return m->sections[i];
/* No need for overlays if it all fits. */
htab->auto_overlay = 0;
htab->params->auto_overlay = 0;
return NULL;
}
@ -1738,69 +1756,6 @@ sort_syms (const void *a, const void *b)
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. */
@ -2102,10 +2057,9 @@ copy_callee (struct function_info *caller, const struct call_info *call)
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);
@ -2127,7 +2081,7 @@ mark_functions_via_relocs (asection *sec,
void *psyms;
static bfd_boolean warned;
if (!interesting_section (sec, info->output_bfd)
if (!interesting_section (sec)
|| sec->reloc_count == 0)
return TRUE;
@ -2158,7 +2112,7 @@ mark_functions_via_relocs (asection *sec,
&& 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;
}
@ -2167,8 +2121,7 @@ mark_functions_via_relocs (asection *sec,
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;
@ -2198,7 +2151,7 @@ mark_functions_via_relocs (asection *sec,
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;
}
@ -2409,7 +2362,7 @@ discover_functions (struct bfd_link_info *info)
{
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;
@ -2447,7 +2400,7 @@ discover_functions (struct bfd_link_info *info)
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;
@ -2489,7 +2442,7 @@ discover_functions (struct bfd_link_info *info)
}
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);
}
@ -2530,7 +2483,7 @@ discover_functions (struct bfd_link_info *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;
@ -2565,7 +2518,7 @@ discover_functions (struct bfd_link_info *info)
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;
@ -2724,7 +2677,7 @@ remove_cycles (struct function_info *fun,
}
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);
@ -2784,7 +2737,7 @@ build_call_tree (struct bfd_link_info *info)
/* 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;
@ -2863,7 +2816,7 @@ mark_overlay_section (struct function_info *fun,
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;
@ -3119,6 +3072,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size)
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;
@ -3150,6 +3104,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size)
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;
@ -3181,7 +3136,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_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)
@ -3199,7 +3154,7 @@ auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int 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);
}
@ -3386,7 +3341,7 @@ sum_stack (struct function_info *fun,
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);
@ -3477,12 +3432,11 @@ sort_bfds (const void *a, const void *b)
/* 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;
@ -3539,13 +3493,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
{
/* 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. */
@ -3637,7 +3585,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
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
@ -3678,7 +3626,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
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;
@ -3696,7 +3644,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
{
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;
@ -3761,22 +3709,23 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
}
/* 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;
@ -3880,8 +3829,8 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
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);
@ -3895,8 +3844,9 @@ spu_elf_auto_overlay (struct bfd_link_info *info,
/* 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))
@ -3905,11 +3855,12 @@ spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
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;
@ -3926,11 +3877,11 @@ spu_elf_final_link (bfd *output_bfd, struct bfd_link_info *info)
{
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);
@ -3983,7 +3934,7 @@ spu_elf_relocate_section (bfd *output_bfd,
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;
@ -3991,7 +3942,8 @@ spu_elf_relocate_section (bfd *output_bfd,
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));

View file

@ -18,6 +18,48 @@
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
struct spu_elf_params
{
/* Stash various callbacks for --auto-overlay. */
void (*place_spu_section) (asection *, asection *, const char *);
bfd_size_type (*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
/* Type of overlays, enum _ovly_flavour. */
unsigned int ovly_flavour : 2;
/* 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 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;
/* Range of valid addresses for loadable sections. */
bfd_vma local_store_lo;
bfd_vma local_store_hi;
/* Control --auto-overlay feature. */
unsigned int auto_overlay_fixed;
unsigned int auto_overlay_reserved;
int extra_stack_space;
};
/* Extra info kept for SPU sections. */
struct spu_elf_stack_info;
@ -45,22 +87,25 @@ struct _spu_elf_section_data
#define spu_elf_section_data(sec) \
((struct _spu_elf_section_data *) elf_section_data (sec))
enum _ovly_flavour
{
ovly_compact,
ovly_normal,
ovly_none
};
struct _ovl_stream
{
const void *start;
const void *end;
};
extern void spu_elf_setup (struct bfd_link_info *, struct spu_elf_params *);
extern void spu_elf_plugin (int);
extern bfd_boolean spu_elf_open_builtin_lib (bfd **,
const struct _ovl_stream *);
extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *, int, int);
extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *);
extern bfd_boolean spu_elf_find_overlays (struct bfd_link_info *);
extern int spu_elf_size_stubs (struct bfd_link_info *,
void (*) (asection *, asection *, const char *),
int);
extern bfd_boolean spu_elf_build_stubs (struct bfd_link_info *, int);
extern asection *spu_elf_check_vma (struct bfd_link_info *, int,
unsigned int, unsigned int, unsigned int,
unsigned int, int, void (*) (void),
FILE *(*) (void), void (*) (void));
extern int spu_elf_size_stubs (struct bfd_link_info *);
extern bfd_boolean spu_elf_build_stubs (struct bfd_link_info *);
extern asection *spu_elf_check_vma (struct bfd_link_info *);

View file

@ -1,3 +1,13 @@
2008-12-10 Alan Modra <amodra@bigpond.net.au>
* emultempl/spuelf.em (params): New var, used instead of various others.
Adjust use throughout file.
(spu_after_open): Call spu_elf_setup.
(spu_place_special_section): Tidy.
(spu_elf_load_ovl_mgr): Return total size of sections loaded. Move
code setting overlay section alignment to..
(spu_before_allocation): ..here.
2008-12-03 Nick Clifton <nickc@redhat.com>
* NEWS: Mention new feature.

View file

@ -26,31 +26,23 @@ fragment <<EOF
#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;
@ -86,12 +78,19 @@ is_spu_target (void)
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, &params);
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 ();
}
@ -112,7 +111,9 @@ spu_place_special_section (asection *s, asection *o, const char *output_name)
{
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)
@ -130,13 +131,13 @@ spu_place_special_section (asection *s, asection *o, const char *output_name)
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);
@ -171,24 +172,13 @@ spu_elf_load_ovl_mgr (void)
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. */
@ -198,7 +188,7 @@ spu_before_allocation (void)
{
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. */
@ -210,16 +200,30 @@ spu_before_allocation (void)
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)
@ -324,25 +328,18 @@ gld${EMULATION_NAME}_finish (void)
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");
}
@ -574,24 +571,24 @@ PARSE_AND_LIST_ARGS_CASES='
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;
}
@ -600,15 +597,15 @@ PARSE_AND_LIST_ARGS_CASES='
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;
@ -617,17 +614,17 @@ PARSE_AND_LIST_ARGS_CASES='
/* 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);
}
@ -636,7 +633,7 @@ PARSE_AND_LIST_ARGS_CASES='
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);
}
@ -645,14 +642,14 @@ PARSE_AND_LIST_ARGS_CASES='
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;