This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: SPU overlay update
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Fri, 14 Mar 2008 15:16:02 +1030
- Subject: Re: SPU overlay update
- References: <20080128055644.GA9974@bubble.grove.modra.org> <20080311093220.GA19543@bubble.grove.modra.org>
This fixes more problems with mismatches between process_stubs, the
function that counts and builds overlay stubs and relocate_section.
relocate_section was missing a test to ignore !SEC_ALLOC sections.
We also now create stubs for jump tables, enabling switch cases to
live in different overlays.
bfd/
* elf32-spu.c (process_stubs, spu_elf_relocate_section): Move
common code to..
(maybe_needs_stub): ..here, a new function that also omits stubs
for .eh_frame, and..
(needs_ovl_stub): ..here. Create stubs for labels in code section
referenced by switch jump table.
(spu_elf_find_overlays): Set htab->ovly_load and htab->ovly_return.
(enum _insn_type): Delete.
(enum _stub_type): New.
(count_stub, build_stub): Adjust.
(allocate_spuear_stubs, build_spuear_stubs): Adjust.
ld/
* emultempl/spuelf.em (gld${EMULATION_NAME}_finish): Protect
spu_elf_build_stubs with is_spu_target.
ld/testsuite/
* ld-spu/ovl2.s: Make setjmp global.
* ld-spu/ovl2.d: Update.
Index: bfd/elf32-spu.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-spu.c,v
retrieving revision 1.33
diff -u -p -r1.33 elf32-spu.c
--- bfd/elf32-spu.c 11 Mar 2008 23:23:23 -0000 1.33
+++ bfd/elf32-spu.c 14 Mar 2008 04:06:57 -0000
@@ -559,6 +559,10 @@ spu_elf_find_overlays (bfd *output_bfd,
htab->num_overlays = ovl_index;
htab->num_buf = num_buf;
htab->ovl_sec = alloc_sec;
+ htab->ovly_load = elf_link_hash_lookup (&htab->elf, "__ovly_load",
+ FALSE, FALSE, FALSE);
+ htab->ovly_return = elf_link_hash_lookup (&htab->elf, "__ovly_return",
+ FALSE, FALSE, FALSE);
return ovl_index != 0;
}
@@ -617,53 +621,156 @@ is_hint (const unsigned char *insn)
return (insn[0] & 0xfc) == 0x10;
}
-/* Return TRUE if this reloc symbol should possibly go via an overlay stub. */
+/* True if INPUT_SECTION might need overlay stubs. */
static bfd_boolean
-needs_ovl_stub (const char *sym_name,
+maybe_needs_stubs (asection *input_section, bfd *output_bfd)
+{
+ /* 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)
+ return FALSE;
+
+ /* Don't create stubs for .eh_frame references. */
+ if (strcmp (input_section->name, ".eh_frame") == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+enum _stub_type
+{
+ no_stub,
+ ovl_stub,
+ nonovl_stub,
+ stub_error
+};
+
+/* Return non-zero if this reloc symbol should go via an overlay stub.
+ Return 2 if the stub must be in non-overlay area. */
+
+static enum _stub_type
+needs_ovl_stub (struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym,
asection *sym_sec,
asection *input_section,
- struct spu_link_hash_table *htab,
- bfd_boolean is_branch)
+ Elf_Internal_Rela *irela,
+ bfd_byte *contents,
+ struct bfd_link_info *info)
{
- if (htab->num_overlays == 0)
- return FALSE;
+ struct spu_link_hash_table *htab = spu_hash_table (info);
+ enum elf_spu_reloc_type r_type;
+ unsigned int sym_type;
+ bfd_boolean branch;
+ enum _stub_type ret = no_stub;
if (sym_sec == NULL
|| sym_sec->output_section == NULL
+ || sym_sec->output_section->owner != info->output_bfd
|| spu_elf_section_data (sym_sec->output_section) == NULL)
- return FALSE;
+ return ret;
- /* setjmp always goes via an overlay stub, because then the return
- and hence the longjmp goes via __ovly_return. That magically
- makes setjmp/longjmp between overlays work. */
- if (strncmp (sym_name, "setjmp", 6) == 0
- && (sym_name[6] == '\0' || sym_name[6] == '@'))
- return TRUE;
+ if (h != NULL)
+ {
+ /* Ensure no stubs for user supplied overlay manager syms. */
+ if (h == htab->ovly_load || h == htab->ovly_return)
+ return ret;
+
+ /* setjmp always goes via an overlay stub, because then the return
+ and hence the longjmp goes via __ovly_return. That magically
+ makes setjmp/longjmp between overlays work. */
+ if (strncmp (h->root.root.string, "setjmp", 6) == 0
+ && (h->root.root.string[6] == '\0' || h->root.root.string[6] == '@'))
+ ret = ovl_stub;
+ }
/* 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)
- return FALSE;
+ return ret;
+
+ if (h != NULL)
+ sym_type = h->type;
+ else
+ sym_type = ELF_ST_TYPE (sym->st_info);
+
+ r_type = ELF32_R_TYPE (irela->r_info);
+ branch = FALSE;
+ if (r_type == R_SPU_REL16 || r_type == R_SPU_ADDR16)
+ {
+ bfd_byte insn[4];
+
+ if (contents == NULL)
+ {
+ contents = insn;
+ if (!bfd_get_section_contents (input_section->owner,
+ input_section,
+ contents,
+ irela->r_offset, 4))
+ return stub_error;
+ }
+ else
+ contents += irela->r_offset;
+
+ if (is_branch (contents) || is_hint (contents))
+ {
+ branch = TRUE;
+ if ((contents[0] & 0xfd) == 0x31
+ && sym_type != STT_FUNC
+ && contents == insn)
+ {
+ /* It's common for people to write assembly and forget
+ to give function symbols the right type. Handle
+ calls to such symbols, but warn so that (hopefully)
+ people will fix their code. We need the symbol
+ type to be correct to distinguish function pointer
+ initialisation from other pointer initialisations. */
+ const char *sym_name;
+
+ if (h != NULL)
+ sym_name = h->root.root.string;
+ else
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ symtab_hdr = &elf_tdata (input_section->owner)->symtab_hdr;
+ sym_name = bfd_elf_sym_name (input_section->owner,
+ symtab_hdr,
+ sym,
+ sym_sec);
+ }
+ (*_bfd_error_handler) (_("warning: call to non-function"
+ " symbol %s defined in %B"),
+ sym_sec->owner, sym_name);
+
+ }
+ }
+ }
+
+ if (sym_type != STT_FUNC
+ && !branch
+ && (sym_sec->flags & SEC_CODE) == 0)
+ return ret;
/* A reference from some other section to a symbol in an overlay
section needs a stub. */
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index
!= spu_elf_section_data (input_section->output_section)->u.o.ovl_index)
- return TRUE;
+ return ovl_stub;
/* If this insn isn't a branch then we are possibly taking the
address of a function and passing it out somehow. */
- return !is_branch;
+ return !branch && sym_type == STT_FUNC ? nonovl_stub : ret;
}
-enum _insn_type { non_branch, branch, call };
-
static bfd_boolean
count_stub (struct spu_link_hash_table *htab,
bfd *ibfd,
asection *isec,
- enum _insn_type insn_type,
+ enum _stub_type stub_type,
struct elf_link_hash_entry *h,
const Elf_Internal_Rela *irela)
{
@@ -676,7 +783,7 @@ count_stub (struct spu_link_hash_table *
If it isn't a branch, then we are taking the address of
this function so need a stub in the non-overlay area
for it. One stub per function. */
- if (insn_type != non_branch)
+ if (stub_type != nonovl_stub)
ovl = spu_elf_section_data (isec->output_section)->u.o.ovl_index;
if (h != NULL)
@@ -763,7 +870,7 @@ static bfd_boolean
build_stub (struct spu_link_hash_table *htab,
bfd *ibfd,
asection *isec,
- enum _insn_type insn_type,
+ enum _stub_type stub_type,
struct elf_link_hash_entry *h,
const Elf_Internal_Rela *irela,
bfd_vma dest,
@@ -775,7 +882,7 @@ build_stub (struct spu_link_hash_table *
bfd_vma addend, val, from, to;
ovl = 0;
- if (insn_type != non_branch)
+ if (stub_type != nonovl_stub)
ovl = spu_elf_section_data (isec->output_section)->u.o.ovl_index;
if (h != NULL)
@@ -908,7 +1015,7 @@ allocate_spuear_stubs (struct elf_link_h
{
struct spu_link_hash_table *htab = inf;
- count_stub (htab, NULL, NULL, non_branch, h, NULL);
+ count_stub (htab, NULL, NULL, nonovl_stub, h, NULL);
}
return TRUE;
@@ -926,7 +1033,7 @@ build_spuear_stubs (struct elf_link_hash
{
struct spu_link_hash_table *htab = inf;
- build_stub (htab, NULL, NULL, non_branch, h, NULL,
+ build_stub (htab, NULL, NULL, nonovl_stub, h, NULL,
h->root.u.def.value, h->root.u.def.section);
}
@@ -971,15 +1078,10 @@ process_stubs (bfd *output_bfd,
/* If there aren't any relocs, then there's nothing more to do. */
if ((isec->flags & SEC_RELOC) == 0
- || (isec->flags & SEC_ALLOC) == 0
- || (isec->flags & SEC_LOAD) == 0
|| isec->reloc_count == 0)
continue;
- /* If this section is a link-once section that will be
- discarded, then don't create any stubs. */
- if (isec->output_section == NULL
- || isec->output_section->owner != output_bfd)
+ if (!maybe_needs_stubs (isec, output_bfd))
continue;
/* Get the relocs. */
@@ -998,9 +1100,7 @@ process_stubs (bfd *output_bfd,
asection *sym_sec;
Elf_Internal_Sym *sym;
struct elf_link_hash_entry *h;
- const char *sym_name;
- unsigned int sym_type;
- enum _insn_type insn_type;
+ enum _stub_type stub_type;
r_type = ELF32_R_TYPE (irela->r_info);
r_indx = ELF32_R_SYM (irela->r_info);
@@ -1023,69 +1123,12 @@ process_stubs (bfd *output_bfd,
if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, ibfd))
goto error_ret_free_internal;
- if (sym_sec == NULL
- || sym_sec->output_section == NULL
- || sym_sec->output_section->owner != output_bfd)
- continue;
-
- /* Ensure no stubs for user supplied overlay manager syms. */
- if (h != NULL
- && (strcmp (h->root.root.string, "__ovly_load") == 0
- || strcmp (h->root.root.string, "__ovly_return") == 0))
- continue;
-
- insn_type = non_branch;
- if (r_type == R_SPU_REL16
- || r_type == R_SPU_ADDR16)
- {
- unsigned char insn[4];
-
- if (!bfd_get_section_contents (ibfd, isec, insn,
- irela->r_offset, 4))
- goto error_ret_free_internal;
-
- if (is_branch (insn) || is_hint (insn))
- {
- insn_type = branch;
- if ((insn[0] & 0xfd) == 0x31)
- insn_type = call;
- }
- }
-
- /* We are only interested in function symbols. */
- if (h != NULL)
- {
- sym_type = h->type;
- sym_name = h->root.root.string;
- }
- else
- {
- sym_type = ELF_ST_TYPE (sym->st_info);
- sym_name = bfd_elf_sym_name (sym_sec->owner,
- symtab_hdr,
- sym,
- sym_sec);
- }
-
- if (sym_type != STT_FUNC)
- {
- /* It's common for people to write assembly and forget
- to give function symbols the right type. Handle
- calls to such symbols, but warn so that (hopefully)
- people will fix their code. We need the symbol
- type to be correct to distinguish function pointer
- initialisation from other pointer initialisation. */
- if (insn_type == call)
- (*_bfd_error_handler) (_("warning: call to non-function"
- " symbol %s defined in %B"),
- sym_sec->owner, sym_name);
- else if (insn_type == non_branch)
- continue;
- }
-
- if (!needs_ovl_stub (sym_name, sym_sec, isec, htab,
- insn_type != non_branch))
+ stub_type = needs_ovl_stub (h, sym, sym_sec, isec, irela,
+ NULL, info);
+ if (stub_type == no_stub)
continue;
+ else if (stub_type == stub_error)
+ goto error_ret_free_internal;
if (htab->stub_count == NULL)
{
@@ -1098,7 +1141,7 @@ process_stubs (bfd *output_bfd,
if (!build)
{
- if (!count_stub (htab, ibfd, isec, insn_type, h, irela))
+ if (!count_stub (htab, ibfd, isec, stub_type, h, irela))
goto error_ret_free_internal;
}
else
@@ -1110,7 +1153,7 @@ process_stubs (bfd *output_bfd,
else
dest = sym->st_value;
dest += irela->r_addend;
- if (!build_stub (htab, ibfd, isec, insn_type, h, irela,
+ if (!build_stub (htab, ibfd, isec, stub_type, h, irela,
dest, sym_sec))
goto error_ret_free_internal;
}
@@ -2680,8 +2723,11 @@ spu_elf_relocate_section (bfd *output_bf
struct spu_link_hash_table *htab;
int ret = TRUE;
bfd_boolean emit_these_relocs = FALSE;
+ bfd_boolean stubs;
htab = spu_hash_table (info);
+ stubs = (htab->stub_sec != NULL
+ && maybe_needs_stubs (input_section, output_bfd));
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd));
@@ -2761,34 +2807,18 @@ spu_elf_relocate_section (bfd *output_bf
/* If this symbol is in an overlay area, we may need to relocate
to the overlay stub. */
addend = rel->r_addend;
- if (htab->stub_sec != NULL
- && sec != NULL
- && sec->output_section != NULL
- && sec->output_section->owner == output_bfd
- && (h == NULL
- || (h != htab->ovly_load && h != htab->ovly_return)))
- {
- bfd_boolean branch;
- unsigned int sym_type;
-
- branch = FALSE;
- if (r_type == R_SPU_REL16
- || r_type == R_SPU_ADDR16)
- branch = (is_branch (contents + rel->r_offset)
- || is_hint (contents + rel->r_offset));
-
- if (h != NULL)
- sym_type = h->type;
- else
- sym_type = ELF_ST_TYPE (sym->st_info);
+ if (stubs)
+ {
+ enum _stub_type stub_type;
- if ((sym_type == STT_FUNC || branch)
- && needs_ovl_stub (sym_name, sec, input_section, htab, branch))
+ stub_type = needs_ovl_stub (h, sym, sec, input_section, rel,
+ contents, info);
+ if (stub_type != no_stub)
{
unsigned int ovl = 0;
struct got_entry *g, **head;
- if (branch)
+ if (stub_type != nonovl_stub)
ovl = (spu_elf_section_data (input_section->output_section)
->u.o.ovl_index);
Index: ld/emultempl/spuelf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/spuelf.em,v
retrieving revision 1.16
diff -u -p -r1.16 spuelf.em
--- ld/emultempl/spuelf.em 15 Feb 2008 03:35:53 -0000 1.16
+++ ld/emultempl/spuelf.em 14 Mar 2008 03:18:08 -0000
@@ -229,20 +229,23 @@ gld${EMULATION_NAME}_finish (void)
gld${EMULATION_NAME}_map_segments (need_laying_out);
- if (is_spu_target () && local_store_lo < local_store_hi)
+ if (is_spu_target ())
{
- asection *s;
+ if (local_store_lo < local_store_hi)
+ {
+ asection *s;
+
+ s = spu_elf_check_vma (link_info.output_bfd,
+ local_store_lo, local_store_hi);
+ if (s != NULL)
+ einfo ("%X%P: %A exceeds local store range\n", s);
+ }
- s = spu_elf_check_vma (link_info.output_bfd,
- local_store_lo, local_store_hi);
- if (s != NULL)
- einfo ("%X%P: %A exceeds local store range\n", s);
+ if (!spu_elf_build_stubs (&link_info,
+ emit_stub_syms || link_info.emitrelocations))
+ einfo ("%X%P: can not build overlay stubs: %E\n");
}
- if (!spu_elf_build_stubs (&link_info,
- emit_stub_syms || link_info.emitrelocations))
- einfo ("%X%P: can not build overlay stubs: %E\n");
-
finish_default ();
}
Index: ld/testsuite/ld-spu/ovl2.s
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-spu/ovl2.s,v
retrieving revision 1.1
diff -u -p -r1.1 ovl2.s
--- ld/testsuite/ld-spu/ovl2.s 27 Mar 2007 08:36:27 -0000 1.1
+++ ld/testsuite/ld-spu/ovl2.s 14 Mar 2008 03:18:10 -0000
@@ -7,6 +7,7 @@ _start:
br _start
.type setjmp,@function
+ .global setjmp
setjmp:
bi lr
.size setjmp,.-setjmp
Index: ld/testsuite/ld-spu/ovl2.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-spu/ovl2.d,v
retrieving revision 1.7
diff -u -p -r1.7 ovl2.d
--- ld/testsuite/ld-spu/ovl2.d 7 Feb 2008 11:03:06 -0000 1.7
+++ ld/testsuite/ld-spu/ovl2.d 14 Mar 2008 03:18:10 -0000
@@ -9,7 +9,7 @@ Disassembly of section \.text:
00000100 <_start>:
.* brsl \$0,.* <00000000\.ovl_call\.f1_a1>.*
.*SPU_REL16 f1_a1
-.* brsl \$0,.* <00000000\.ovl_call\.10:4>.*
+.* brsl \$0,.* <00000000\.ovl_call\.setjmp>.*
.*SPU_REL16 setjmp
.* br 100 <_start> # 100
.*SPU_REL16 _start
@@ -25,7 +25,7 @@ Disassembly of section \.text:
#.* brsl \$75,.* <__ovly_load>.*
#.*00 04 04 00.*
#
-#00000120 <00000000\.ovl_call.10:4>:
+#00000120 <00000000\.ovl_call.setjmp>:
#.* brsl \$75,.* <__ovly_load>.*
#.*00 00 01 0c.*
#
@@ -39,7 +39,7 @@ Disassembly of section \.text:
.* ila \$79,1024 # 400
.* br .* <__ovly_load>.*
-00000130 <00000000\.ovl_call.10:4>:
+00000130 <00000000\.ovl_call.setjmp>:
.* ila \$78,0
.* lnop
.* ila \$79,268 # 10c
--
Alan Modra
Australia Development Lab, IBM