This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: SPU stack analysis and function splitting
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Mon, 3 Mar 2008 20:34:37 +1030
- Subject: Re: SPU stack analysis and function splitting
- References: <20080228093001.GA26067@bubble.grove.modra.org>
On Thu, Feb 28, 2008 at 08:00:01PM +1030, Alan Modra wrote:
> ... when spu-gcc starts splitting functions into multiple sections.
Another necessary change. Branches from one section to another are
not necesarily to the start of a section and relocs against the branch
destination local symbol will be simplified to a reloc against the
section symbol plus some addend. This leads to more than one entry
into an overlay against the same (section) symbol.
* elf32-spu.c (struct got_entry): Add "addend" field.
(count_stub, build_stub): Use a new stub if relocation addend
differs from existing stubs for this symbol.
(process_stubs): Deal with addends.
(spu_elf_relocate_section, spu_elf_output_symbol_hook): Likewise.
Index: bfd/elf32-spu.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-spu.c,v
retrieving revision 1.30
diff -u -p -r1.30 elf32-spu.c
--- bfd/elf32-spu.c 28 Feb 2008 09:30:27 -0000 1.30
+++ bfd/elf32-spu.c 3 Mar 2008 09:33:56 -0000
@@ -301,6 +301,7 @@ struct got_entry
{
struct got_entry *next;
unsigned int ovl;
+ bfd_vma addend;
bfd_vma stub_addr;
};
@@ -675,6 +676,7 @@ count_stub (struct spu_link_hash_table *
{
unsigned int ovl = 0;
struct got_entry *g, **head;
+ bfd_vma addend;
/* If this instruction is a branch or call, we need a stub
for it. One stub per function per overlay.
@@ -699,28 +701,36 @@ count_stub (struct spu_link_hash_table *
head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info);
}
- /* If we have a stub in the non-overlay area then there's no need
- for one in overlays. */
- g = *head;
- if (g != NULL && g->ovl == 0)
- return TRUE;
+ addend = 0;
+ if (irela != NULL)
+ addend = irela->r_addend;
if (ovl == 0)
{
struct got_entry *gnext;
- /* Need a new non-overlay area stub. Zap other stubs. */
- for (; g != NULL; g = gnext)
+ for (g = *head; g != NULL; g = g->next)
+ if (g->addend == addend && g->ovl == 0)
+ break;
+
+ if (g == NULL)
{
- htab->stub_count[g->ovl] -= 1;
- gnext = g->next;
- free (g);
+ /* Need a new non-overlay area stub. Zap other stubs. */
+ for (g = *head; g != NULL; g = gnext)
+ {
+ gnext = g->next;
+ if (g->addend == addend)
+ {
+ htab->stub_count[g->ovl] -= 1;
+ free (g);
+ }
+ }
}
}
else
{
- for (; g != NULL; g = g->next)
- if (g->ovl == ovl)
+ for (g = *head; g != NULL; g = g->next)
+ if (g->addend == addend && (g->ovl == ovl || g->ovl == 0))
break;
}
@@ -730,6 +740,7 @@ count_stub (struct spu_link_hash_table *
if (g == NULL)
return FALSE;
g->ovl = ovl;
+ g->addend = addend;
g->stub_addr = (bfd_vma) -1;
g->next = *head;
*head = g;
@@ -768,7 +779,7 @@ build_stub (struct spu_link_hash_table *
unsigned int ovl;
struct got_entry *g, **head;
asection *sec;
- bfd_vma val, from, to;
+ bfd_vma addend, val, from, to;
ovl = 0;
if (insn_type != non_branch)
@@ -779,16 +790,19 @@ build_stub (struct spu_link_hash_table *
else
head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info);
- g = *head;
- if (g != NULL && g->ovl == 0 && ovl != 0)
- return TRUE;
+ addend = 0;
+ if (irela != NULL)
+ addend = irela->r_addend;
- for (; g != NULL; g = g->next)
- if (g->ovl == ovl)
+ for (g = *head; g != NULL; g = g->next)
+ if (g->addend == addend && (g->ovl == ovl || g->ovl == 0))
break;
if (g == NULL)
abort ();
+ if (g->ovl == 0 && ovl != 0)
+ return TRUE;
+
if (g->stub_addr != (bfd_vma) -1)
return TRUE;
@@ -1102,6 +1116,7 @@ process_stubs (bfd *output_bfd,
dest = h->root.u.def.value;
else
dest = sym->st_value;
+ dest += irela->r_addend;
if (!build_stub (htab, ibfd, isec, insn_type, h, irela,
dest, sym_sec))
goto error_ret_free_internal;
@@ -2774,7 +2789,7 @@ spu_elf_relocate_section (bfd *output_bf
head = elf_local_got_ents (input_bfd) + r_symndx;
for (g = *head; g != NULL; g = g->next)
- if (g->ovl == ovl || g->ovl == 0)
+ if (g->addend == addend && (g->ovl == ovl || g->ovl == 0))
break;
if (g == NULL)
abort ();
@@ -2883,15 +2898,17 @@ spu_elf_output_symbol_hook (struct bfd_l
&& h->def_regular
&& strncmp (h->root.root.string, "_SPUEAR_", 8) == 0)
{
- struct got_entry *g = h->got.glist;
+ struct got_entry *g;
- if (g != NULL && g->ovl == 0)
- {
- sym->st_shndx = (_bfd_elf_section_from_bfd_section
- (htab->stub_sec[0]->output_section->owner,
- htab->stub_sec[0]->output_section));
- sym->st_value = g->stub_addr;
- }
+ for (g = h->got.glist; g != NULL; g = g->next)
+ if (g->addend == 0 && g->ovl == 0)
+ {
+ sym->st_shndx = (_bfd_elf_section_from_bfd_section
+ (htab->stub_sec[0]->output_section->owner,
+ htab->stub_sec[0]->output_section));
+ sym->st_value = g->stub_addr;
+ break;
+ }
}
return TRUE;
--
Alan Modra
Australia Development Lab, IBM