/* For soft icache. */
unsigned int line_size_log2;
unsigned int num_lines_log2;
+ unsigned int fromelem_size_log2;
/* How much memory we have. */
unsigned int local_store;
void
spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params)
{
+ bfd_vma max_branch_log2;
+
struct spu_link_hash_table *htab = spu_hash_table (info);
htab->params = params;
htab->line_size_log2 = bfd_log2 (htab->params->line_size);
htab->num_lines_log2 = bfd_log2 (htab->params->num_lines);
+
+ /* For the software i-cache, we provide a "from" list whose size
+ is a power-of-two number of quadwords, big enough to hold one
+ byte per outgoing branch. Compute this number here. */
+ max_branch_log2 = bfd_log2 (htab->params->max_branch);
+ htab->fromelem_size_log2 = max_branch_log2 > 4 ? max_branch_log2 - 4 : 0;
}
/* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP
return (*s1)->index - (*s2)->index;
}
-/* Identify overlays in the output bfd, and number them. */
+/* Identify overlays in the output bfd, and number them.
+ Returns 0 on error, 1 if no overlays, 2 if overlays. */
-bfd_boolean
+int
spu_elf_find_overlays (struct bfd_link_info *info)
{
struct spu_link_hash_table *htab = spu_hash_table (info);
unsigned int i, n, ovl_index, num_buf;
asection *s;
bfd_vma ovl_end;
- const char *ovly_mgr_entry;
+ static const char *const entry_names[2][2] = {
+ { "__ovly_load", "__icache_br_handler" },
+ { "__ovly_return", "__icache_call_handler" }
+ };
if (info->output_bfd->section_count < 2)
- return FALSE;
+ return 1;
alloc_sec
= bfd_malloc (info->output_bfd->section_count * sizeof (*alloc_sec));
if (alloc_sec == NULL)
- return FALSE;
+ return 0;
/* Pick out all the alloced sections. */
for (n = 0, s = info->output_bfd->sections; s != NULL; s = s->next)
if (n == 0)
{
free (alloc_sec);
- return FALSE;
+ return 1;
}
/* Sort them by vma. */
{
asection *s0 = alloc_sec[i - 1];
vma_start = s0->vma;
- lma_start = s0->lma;
+ if (strncmp (s0->name, ".ovl.init", 9) != 0)
+ lma_start = s0->lma;
+ else
+ lma_start = s->lma;
ovl_end = (s0->vma
+ ((bfd_vma) 1
<< (htab->num_lines_log2 + htab->line_size_log2)));
"does not start on a cache line.\n"),
s);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return 0;
}
else if (s->size > htab->params->line_size)
{
"is larger than a cache line.\n"),
s);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return 0;
}
alloc_sec[ovl_index++] = s;
"is not in cache area.\n"),
alloc_sec[i-1]);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return 0;
}
else
ovl_end = s->vma + s->size;
"same address.\n"),
s0, s);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return 0;
}
if (ovl_end < s->vma + s->size)
ovl_end = s->vma + s->size;
htab->num_overlays = ovl_index;
htab->num_buf = num_buf;
htab->ovl_sec = alloc_sec;
- ovly_mgr_entry = "__ovly_load";
- if (htab->params->ovly_flavour == ovly_soft_icache)
- ovly_mgr_entry = "__icache_br_handler";
- htab->ovly_entry[0] = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry,
- FALSE, FALSE, FALSE);
- ovly_mgr_entry = "__ovly_return";
- if (htab->params->ovly_flavour == ovly_soft_icache)
- ovly_mgr_entry = "__icache_call_handler";
- htab->ovly_entry[1] = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry,
- FALSE, FALSE, FALSE);
- return ovl_index != 0;
+
+ if (ovl_index == 0)
+ return 1;
+
+ for (i = 0; i < 2; i++)
+ {
+ const char *name;
+ struct elf_link_hash_entry *h;
+
+ name = entry_names[i][htab->params->ovly_flavour];
+ h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
+ if (h == NULL)
+ return 0;
+
+ if (h->root.type == bfd_link_hash_new)
+ {
+ h->root.type = bfd_link_hash_undefined;
+ h->ref_regular = 1;
+ h->ref_regular_nonweak = 1;
+ h->non_elf = 0;
+ }
+ htab->ovly_entry[i] = h;
+ }
+
+ return 2;
}
/* Non-zero to use bra in overlay stubs rather than br. */
if (h != NULL)
{
/* Ensure no stubs for user supplied overlay manager syms. */
- if (h == htab->ovly_entry[0]|| h == htab->ovly_entry[1])
+ if (h == htab->ovly_entry[0] || h == htab->ovly_entry[1])
return ret;
/* setjmp always goes via an overlay stub, because then the return
bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18),
sec->contents + sec->size + 4);
}
- else if (htab->params->ovly_flavour == ovly_soft_icache)
+ else if (htab->params->ovly_flavour == ovly_soft_icache
+ && htab->params->compact_stub)
{
lrlive = 0;
if (stub_type == nonovl_stub)
+ htab->ovly_entry[1]->root.u.def.section->output_offset
+ htab->ovly_entry[1]->root.u.def.section->output_section->vma);
- if (!htab->params->compact_stub)
+ /* The branch that uses this stub goes to stub_addr + 4. We'll
+ set up an xor pattern that can be used by the icache manager
+ to modify this branch to go directly to its destination. */
+ g->stub_addr += 4;
+ br_dest = g->stub_addr;
+ if (irela == NULL)
{
- /* The branch that uses this stub goes to stub_addr + 12. We'll
- set up an xor pattern that can be used by the icache manager
- to modify this branch to go directly to its destination. */
- g->stub_addr += 12;
- br_dest = g->stub_addr;
- if (irela == NULL)
- {
- /* Except in the case of _SPUEAR_ stubs, the branch in
- question is the one in the stub itself. */
- BFD_ASSERT (stub_type == nonovl_stub);
- g->br_addr = g->stub_addr;
- br_dest = to;
- }
-
- bfd_put_32 (sec->owner, dest_ovl - 1,
- sec->contents + sec->size + 0);
- set_id = ((dest_ovl - 1) >> htab->num_lines_log2) + 1;
- bfd_put_32 (sec->owner, (set_id << 18) | (dest & 0x3ffff),
- sec->contents + sec->size + 4);
- bfd_put_32 (sec->owner, (lrlive << 29) | (g->br_addr & 0x3ffff),
- sec->contents + sec->size + 8);
- bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75,
- sec->contents + sec->size + 12);
- patt = dest ^ br_dest;
- if (irela != NULL && ELF32_R_TYPE (irela->r_info) == R_SPU_REL16)
- patt = (dest - g->br_addr) ^ (br_dest - g->br_addr);
- bfd_put_32 (sec->owner, (patt << 5) & 0x007fff80,
- sec->contents + sec->size + 16 + (g->br_addr & 0xf));
+ /* Except in the case of _SPUEAR_ stubs, the branch in
+ question is the one in the stub itself. */
+ BFD_ASSERT (stub_type == nonovl_stub);
+ g->br_addr = g->stub_addr;
+ br_dest = to;
}
- else
- {
- g->stub_addr += 4;
- br_dest = g->stub_addr;
- if (irela == NULL)
- {
- BFD_ASSERT (stub_type == nonovl_stub);
- g->br_addr = g->stub_addr;
- br_dest = to;
- }
- set_id = ((dest_ovl - 1) >> htab->num_lines_log2) + 1;
- bfd_put_32 (sec->owner, (set_id << 18) | (dest & 0x3ffff),
- sec->contents + sec->size);
- bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75,
- sec->contents + sec->size + 4);
- bfd_put_32 (sec->owner, (lrlive << 29) | (g->br_addr & 0x3ffff),
- sec->contents + sec->size + 8);
- patt = dest ^ br_dest;
- if (irela != NULL && ELF32_R_TYPE (irela->r_info) == R_SPU_REL16)
- patt = (dest - g->br_addr) ^ (br_dest - g->br_addr);
- bfd_put_32 (sec->owner, (patt << 5) & 0x007fff80,
- sec->contents + sec->size + 12);
- }
+ set_id = ((dest_ovl - 1) >> htab->num_lines_log2) + 1;
+ bfd_put_32 (sec->owner, (set_id << 18) | (dest & 0x3ffff),
+ sec->contents + sec->size);
+ bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75,
+ sec->contents + sec->size + 4);
+ bfd_put_32 (sec->owner, (lrlive << 29) | (g->br_addr & 0x3ffff),
+ sec->contents + sec->size + 8);
+ patt = dest ^ br_dest;
+ if (irela != NULL && ELF32_R_TYPE (irela->r_info) == R_SPU_REL16)
+ patt = (dest - g->br_addr) ^ (br_dest - g->br_addr);
+ bfd_put_32 (sec->owner, (patt << 5) & 0x007fff80,
+ sec->contents + sec->size + 12);
if (ovl == 0)
/* Extra space for linked list entries. */
flagword flags;
unsigned int i;
asection *stub;
- const char *ovout;
if (!process_stubs (info, FALSE))
return 0;
if (htab->params->ovly_flavour == ovly_soft_icache)
/* Extra space for linked list entries. */
stub->size += htab->stub_count[0] * 16;
- (*htab->params->place_spu_section) (stub, NULL, ".text");
for (i = 0; i < htab->num_overlays; ++i)
{
ovl_stub_size_log2 (htab->params)))
return 0;
stub->size = htab->stub_count[ovl] * ovl_stub_size (htab->params);
- (*htab->params->place_spu_section) (stub, osec, NULL);
}
- flags = (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY);
- htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags);
- if (htab->ovtab == NULL
- || !bfd_set_section_alignment (ibfd, htab->ovtab, 4))
- return 0;
-
if (htab->params->ovly_flavour == ovly_soft_icache)
{
/* Space for icache manager tables.
a) Tag array, one quadword per cache line.
- b) Linked list elements, max_branch per line quadwords. */
- htab->ovtab->size = 16 * ((1 + htab->params->max_branch)
- << htab->num_lines_log2);
+ b) Rewrite "to" list, one quadword per cache line.
+ c) Rewrite "from" list, one byte per outgoing branch (rounded up to
+ a power-of-two number of full quadwords) per cache line. */
+
+ flags = SEC_ALLOC;
+ htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags);
+ if (htab->ovtab == NULL
+ || !bfd_set_section_alignment (ibfd, htab->ovtab, 4))
+ return 0;
+
+ htab->ovtab->size = (16 + 16 + (16 << htab->fromelem_size_log2))
+ << htab->num_lines_log2;
+ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
htab->init = bfd_make_section_anyway_with_flags (ibfd, ".ovini", flags);
if (htab->init == NULL
|| !bfd_set_section_alignment (ibfd, htab->init, 4))
return 0;
htab->init->size = 16;
- (*htab->params->place_spu_section) (htab->init, NULL, ".ovl.init");
}
else
{
. } _ovly_buf_table[];
. */
+ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+ htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags);
+ if (htab->ovtab == NULL
+ || !bfd_set_section_alignment (ibfd, htab->ovtab, 4))
+ return 0;
+
htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4;
}
- ovout = ".data";
- if (htab->params->ovly_flavour == ovly_soft_icache)
- ovout = ".data.icache";
- (*htab->params->place_spu_section) (htab->ovtab, NULL, ovout);
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 = htab->params->ovly_flavour == ovly_soft_icache ? 256 : 16;
- (*htab->params->place_spu_section) (htab->toe, NULL, ".toe");
+ htab->toe->size = 16;
return 2;
}
+/* Called from ld to place overlay manager data sections. This is done
+ after the overlay manager itself is loaded, mainly so that the
+ linker's htab->init section is placed after any other .ovl.init
+ sections. */
+
+void
+spu_elf_place_overlay_data (struct bfd_link_info *info)
+{
+ struct spu_link_hash_table *htab = spu_hash_table (info);
+ unsigned int i;
+ const char *ovout;
+
+ if (htab->stub_count == NULL)
+ return;
+
+ (*htab->params->place_spu_section) (htab->stub_sec[0], NULL, ".text");
+
+ for (i = 0; i < htab->num_overlays; ++i)
+ {
+ asection *osec = htab->ovl_sec[i];
+ unsigned int ovl = spu_elf_section_data (osec)->u.o.ovl_index;
+ (*htab->params->place_spu_section) (htab->stub_sec[ovl], osec, NULL);
+ }
+
+ if (htab->params->ovly_flavour == ovly_soft_icache)
+ (*htab->params->place_spu_section) (htab->init, NULL, ".ovl.init");
+
+ ovout = ".data";
+ if (htab->params->ovly_flavour == ovly_soft_icache)
+ ovout = ".bss";
+ (*htab->params->place_spu_section) (htab->ovtab, NULL, ovout);
+
+ (*htab->params->place_spu_section) (htab->toe, NULL, ".toe");
+}
+
/* Functions to handle embedded spu_ovl.o object. */
static void *
htab->stub_sec[i]->size = 0;
}
- h = htab->ovly_entry[0];
- if (h == NULL)
+ for (i = 0; i < 2; i++)
{
- const char *ovly_mgr_entry = "__ovly_load";
+ h = htab->ovly_entry[i];
+ BFD_ASSERT (h != NULL);
- if (htab->params->ovly_flavour == ovly_soft_icache)
- ovly_mgr_entry = "__icache_br_handler";
- h = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry,
- FALSE, FALSE, FALSE);
- htab->ovly_entry[0] = h;
- }
- BFD_ASSERT (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && h->def_regular);
-
- s = h->root.u.def.section->output_section;
- if (spu_elf_section_data (s)->u.o.ovl_index)
- {
- (*_bfd_error_handler) (_("%s in overlay section"),
- h->root.root.string);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
-
- h = htab->ovly_entry[1];
- if (h == NULL)
- {
- const char *ovly_mgr_entry = "__ovly_return";
-
- if (htab->params->ovly_flavour == ovly_soft_icache)
- ovly_mgr_entry = "__icache_call_handler";
- h = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry,
- FALSE, FALSE, FALSE);
- htab->ovly_entry[1] = h;
- }
- BFD_ASSERT (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && h->def_regular);
-
- s = h->root.u.def.section->output_section;
- if (spu_elf_section_data (s)->u.o.ovl_index)
- {
- (*_bfd_error_handler) (_("%s in overlay section"),
- h->root.root.string);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->def_regular)
+ {
+ s = h->root.u.def.section->output_section;
+ if (spu_elf_section_data (s)->u.o.ovl_index)
+ {
+ (*_bfd_error_handler) (_("%s in overlay section"),
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ }
+ else
+ BFD_ASSERT (0);
}
/* Fill in all the stubs. */
p = htab->ovtab->contents;
if (htab->params->ovly_flavour == ovly_soft_icache)
{
- bfd_vma off, icache_base, linklist;
+ bfd_vma off;
- h = define_ovtab_symbol (htab, "__icache_tagbase");
+ h = define_ovtab_symbol (htab, "__icache_tag_array");
if (h == NULL)
return FALSE;
h->root.u.def.value = 0;
h->size = 16 << htab->num_lines_log2;
off = h->size;
- icache_base = htab->ovl_sec[0]->vma;
- linklist = (htab->ovtab->output_section->vma
- + htab->ovtab->output_offset
- + off);
- for (i = 0; i < htab->params->num_lines; i++)
- {
- bfd_vma line_end = icache_base + ((i + 1) << htab->line_size_log2);
- bfd_vma stub_base = line_end - htab->params->max_branch * 32;
- bfd_vma link_elem = linklist + i * htab->params->max_branch * 16;
- bfd_vma locator = link_elem - stub_base / 2;
-
- bfd_put_32 (htab->ovtab->owner, locator, p + 4);
- bfd_put_16 (htab->ovtab->owner, link_elem, p + 8);
- bfd_put_16 (htab->ovtab->owner, link_elem, p + 10);
- bfd_put_16 (htab->ovtab->owner, link_elem, p + 12);
- bfd_put_16 (htab->ovtab->owner, link_elem, p + 14);
- p += 16;
- }
- h = define_ovtab_symbol (htab, "__icache_linked_list");
+ h = define_ovtab_symbol (htab, "__icache_tag_array_size");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = 16 << htab->num_lines_log2;
+ h->root.u.def.section = bfd_abs_section_ptr;
+
+ h = define_ovtab_symbol (htab, "__icache_rewrite_to");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = off;
+ h->size = 16 << htab->num_lines_log2;
+ off += h->size;
+
+ h = define_ovtab_symbol (htab, "__icache_rewrite_to_size");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = 16 << htab->num_lines_log2;
+ h->root.u.def.section = bfd_abs_section_ptr;
+
+ h = define_ovtab_symbol (htab, "__icache_rewrite_from");
if (h == NULL)
return FALSE;
h->root.u.def.value = off;
- h->size = htab->params->max_branch << (htab->num_lines_log2 + 4);
+ h->size = 16 << (htab->fromelem_size_log2 + htab->num_lines_log2);
off += h->size;
- p += h->size;
+
+ h = define_ovtab_symbol (htab, "__icache_rewrite_from_size");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = 16 << (htab->fromelem_size_log2
+ + htab->num_lines_log2);
+ h->root.u.def.section = bfd_abs_section_ptr;
+
+ h = define_ovtab_symbol (htab, "__icache_log2_fromelemsize");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = htab->fromelem_size_log2;
+ h->root.u.def.section = bfd_abs_section_ptr;
h = define_ovtab_symbol (htab, "__icache_base");
if (h == NULL)
h->root.u.def.section = bfd_abs_section_ptr;
h->size = htab->num_buf << htab->line_size_log2;
+ h = define_ovtab_symbol (htab, "__icache_linesize");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = 1 << htab->line_size_log2;
+ h->root.u.def.section = bfd_abs_section_ptr;
+
+ h = define_ovtab_symbol (htab, "__icache_log2_linesize");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = htab->line_size_log2;
+ h->root.u.def.section = bfd_abs_section_ptr;
+
h = define_ovtab_symbol (htab, "__icache_neg_log2_linesize");
if (h == NULL)
return FALSE;
h->root.u.def.value = -htab->line_size_log2;
h->root.u.def.section = bfd_abs_section_ptr;
+ h = define_ovtab_symbol (htab, "__icache_cachesize");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = 1 << (htab->num_lines_log2 + htab->line_size_log2);
+ h->root.u.def.section = bfd_abs_section_ptr;
+
+ h = define_ovtab_symbol (htab, "__icache_log2_cachesize");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = htab->num_lines_log2 + htab->line_size_log2;
+ h->root.u.def.section = bfd_abs_section_ptr;
+
+ h = define_ovtab_symbol (htab, "__icache_neg_log2_cachesize");
+ if (h == NULL)
+ return FALSE;
+ h->root.u.def.value = -(htab->num_lines_log2 + htab->line_size_log2);
+ h->root.u.def.section = bfd_abs_section_ptr;
+
if (htab->init != NULL && htab->init->size != 0)
{
htab->init->contents = bfd_zalloc (htab->init->owner,
return FALSE;
h->root.u.def.section = htab->toe;
h->root.u.def.value = 0;
- h->size = htab->params->ovly_flavour == ovly_soft_icache ? 16 * 16 : 16;
+ h->size = 16;
return TRUE;
}
callee->fun->is_func = TRUE;
}
else if (callee->fun->start == NULL)
- callee->fun->start = caller;
+ {
+ struct function_info *caller_start = caller;
+ while (caller_start->start)
+ caller_start = caller_start->start;
+
+ if (caller_start != callee->fun)
+ callee->fun->start = caller_start;
+ }
else
{
struct function_info *callee_start;
if (!fun->sec->linker_mark
&& (htab->params->ovly_flavour != ovly_soft_icache
|| htab->params->non_ia_text
- || strncmp (fun->sec->name, ".text.ia.", 9) == 0))
+ || strncmp (fun->sec->name, ".text.ia.", 9) == 0
+ || strcmp (fun->sec->name, ".init") == 0
+ || strcmp (fun->sec->name, ".fini") == 0))
{
unsigned int size;
fixed_size += htab->non_ovly_stub * 16;
/* Space for icache manager tables.
a) Tag array, one quadword per cache line.
- - word 0: ia address of present line, init to zero.
- - word 1: link locator. link_elem=stub_addr/2+locator
- - halfwords 4-7: head/tail pointers for linked lists. */
+ - word 0: ia address of present line, init to zero. */
+ fixed_size += 16 << htab->num_lines_log2;
+ /* b) Rewrite "to" list, one quadword per cache line. */
fixed_size += 16 << htab->num_lines_log2;
- /* b) Linked list elements, max_branch per line. */
- fixed_size += htab->params->max_branch << (htab->num_lines_log2 + 4);
- /* c) Indirect branch descriptors, 8 quadwords. */
- fixed_size += 8 * 16;
- /* d) Pointers to __ea backing store, 16 quadwords. */
- fixed_size += 16 * 16;
+ /* c) Rewrite "from" list, one byte per outgoing branch (rounded up
+ to a power-of-two number of full quadwords) per cache line. */
+ fixed_size += 16 << (htab->fromelem_size_log2
+ + htab->num_lines_log2);
+ /* d) Pointer to __ea backing store (toe), 1 quadword. */
+ fixed_size += 16;
}
else
{
bfd_reloc_status_type r;
bfd_boolean unresolved_reloc;
bfd_boolean warned;
- bfd_boolean overlay_encoded;
enum _stub_type stub_type;
r_symndx = ELF32_R_SYM (rel->r_info);
is_ea_sym = (ea != NULL
&& sec != NULL
&& sec->output_section == ea);
- overlay_encoded = FALSE;
/* If this symbol is in an overlay area, we may need to relocate
to the overlay stub. */
{
/* For soft icache, encode the overlay index into addresses. */
if (htab->params->ovly_flavour == ovly_soft_icache
+ && (r_type == R_SPU_ADDR16_HI
+ || r_type == R_SPU_ADDR32 || r_type == R_SPU_REL32)
&& !is_ea_sym)
{
unsigned int ovl = overlay_index (sec);
{
unsigned int set_id = ((ovl - 1) >> htab->num_lines_log2) + 1;
relocation += set_id << 18;
- overlay_encoded = TRUE;
}
}
}
switch (r)
{
case bfd_reloc_overflow:
- /* FIXME: We don't want to warn on most references
- within an overlay to itself, but this may silence a
- warning that should be reported. */
- if (overlay_encoded && sec == input_section)
- break;
if (!((*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), sym_name, howto->name,
(bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
{
asection *toe, *s;
- struct elf_segment_map *m;
+ struct elf_segment_map *m, *m_overlay;
+ struct elf_segment_map **p, **p_overlay;
unsigned int i;
if (info == NULL)
break;
}
+
+ /* Some SPU ELF loaders ignore the PF_OVERLAY flag and just load all
+ PT_LOAD segments. This can cause the .ovl.init section to be
+ overwritten with the contents of some overlay segment. To work
+ around this issue, we ensure that all PF_OVERLAY segments are
+ sorted first amongst the program headers; this ensures that even
+ with a broken loader, the .ovl.init section (which is not marked
+ as PF_OVERLAY) will be placed into SPU local store on startup. */
+
+ /* Move all overlay segments onto a separate list. */
+ p = &elf_tdata (abfd)->segment_map;
+ p_overlay = &m_overlay;
+ while (*p != NULL)
+ {
+ if ((*p)->p_type == PT_LOAD && (*p)->count == 1
+ && spu_elf_section_data ((*p)->sections[0])->u.o.ovl_index != 0)
+ {
+ struct elf_segment_map *m = *p;
+ *p = m->next;
+ *p_overlay = m;
+ p_overlay = &m->next;
+ continue;
+ }
+
+ p = &((*p)->next);
+ }
+
+ /* Re-insert overlay segments at the head of the segment map. */
+ *p_overlay = elf_tdata (abfd)->segment_map;
+ elf_tdata (abfd)->segment_map = m_overlay;
+
return TRUE;
}
#define elf_backend_can_gc_sections 1
#define bfd_elf32_bfd_reloc_type_lookup spu_elf_reloc_type_lookup
-#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup
+#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup
#define elf_info_to_howto spu_elf_info_to_howto
#define elf_backend_count_relocs spu_elf_count_relocs
#define elf_backend_relocate_section spu_elf_relocate_section