bfd/
* 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:
parent
b0c4170911
commit
64615358cc
5 changed files with 342 additions and 313 deletions
|
@ -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
|
||||
|
|
398
bfd/elf32-spu.c
398
bfd/elf32-spu.c
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 *);
|
||||
|
|
10
ld/ChangeLog
10
ld/ChangeLog
|
@ -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.
|
||||
|
|
|
@ -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, ¶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 ();
|
||||
}
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue