This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: spu overlays and setjmp/longjmp


Some fixes for overlay stubs.  Firstly, my fix for setjmp/longjmp in
http://sourceware.org/ml/binutils/2007-03/msg00178.html was
incomplete.  A stub for setjmp was generated (due to the
spu_elf_size_stubs change), but then not actually used due to lack of
a corresponding change in spu_elf_relocate_section.  Using a common
"needs_ovl_stub" function in both places should prevent this silly
mistake reoccurring.  Secondly, it was wrong to use the input section
id in the stub name.  This could generate unnecessary stubs and trigger
an assertion failure.  Finally, we need relocs on all function calls
to ensure we have overlay stubs generated in certain corner cases.  I
also need the relocs for some future work.

bfd/
	* elf32-spu.c (spu_stub_name): Don't put input section in stub name.
	Remove input_sec param.  Adjust all calls.
	(write_one_stub): Adjust stub symbol.
	(needs_ovl_stub): New function, extracted from..
	(spu_elf_size_stubs): ..here.
	(spu_elf_relocate_section): Use needs_ovl_stub.
gas/
	* config/tc-spu.c: Don't include opcode/spu.h.
	(md_assemble): Set tc_fix_data.insn_tag and arg_format.
	(md_apply_fix): Adjust.
	* config/tc-spu.h: Include opcode/spu.h.
	(struct tc_fix_info): New.
	(TC_FIX_TYPE, TC_INIT_FIX_DATA): Adjust.
	(TC_FORCE_RELOCATION): Define.
ld/testsuite/
	* ld-spu/ovl.s (f4_a2): Tail call.
	* ld-spu/ovl.d: Add --emit-relocs to ld options, -r to objdump.
	Update expected results.

Index: bfd/elf32-spu.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-spu.c,v
retrieving revision 1.6
diff -u -p -r1.6 elf32-spu.c
--- bfd/elf32-spu.c	17 Mar 2007 02:56:37 -0000	1.6
+++ bfd/elf32-spu.c	22 Mar 2007 23:32:33 -0000
@@ -425,14 +425,11 @@ get_sym_h (struct elf_link_hash_entry **
   return TRUE;
 }
 
-/* Build a name for an entry in the stub hash table.  The input section
-   id isn't really necessary but we add that in for consistency with
-   ppc32 and ppc64 stub names.  We can't use a local symbol name
-   because ld -r might generate duplicate local symbols.  */
+/* Build a name for an entry in the stub hash table.  We can't use a
+   local symbol name because ld -r might generate duplicate local symbols.  */
 
 static char *
-spu_stub_name (const asection *input_sec,
-	       const asection *sym_sec,
+spu_stub_name (const asection *sym_sec,
 	       const struct elf_link_hash_entry *h,
 	       const Elf_Internal_Rela *rel)
 {
@@ -441,26 +438,24 @@ spu_stub_name (const asection *input_sec
 
   if (h)
     {
-      len = 8 + 1 + strlen (h->root.root.string) + 1 + 8 + 1;
+      len = strlen (h->root.root.string) + 1 + 8 + 1;
       stub_name = bfd_malloc (len);
       if (stub_name == NULL)
 	return stub_name;
 
-      sprintf (stub_name, "%08x.%s+%x",
-	       input_sec->id & 0xffffffff,
+      sprintf (stub_name, "%s+%x",
 	       h->root.root.string,
 	       (int) rel->r_addend & 0xffffffff);
       len -= 8;
     }
   else
     {
-      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
+      len = 8 + 1 + 8 + 1 + 8 + 1;
       stub_name = bfd_malloc (len);
       if (stub_name == NULL)
 	return stub_name;
 
-      sprintf (stub_name, "%08x.%x:%x+%x",
-	       input_sec->id & 0xffffffff,
+      sprintf (stub_name, "%x:%x+%x",
 	       sym_sec->id & 0xffffffff,
 	       (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
 	       (int) rel->r_addend & 0xffffffff);
@@ -682,6 +677,45 @@ is_branch (const unsigned char *insn)
 	  || (insn[0] & 0xfc) == 0x10);
 }
 
+/* Return TRUE if this reloc symbol should possibly go via an overlay stub.  */
+
+static bfd_boolean
+needs_ovl_stub (const char *sym_name,
+		asection *sym_sec,
+		asection *input_section,
+		struct spu_link_hash_table *htab,
+		bfd_boolean is_branch)
+{
+  if (htab->num_overlays == 0)
+    return FALSE;
+
+  if (sym_sec == NULL
+      || sym_sec->output_section == NULL)
+    return FALSE;
+
+  /* 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;
+
+  /* Usually, symbols in non-overlay sections don't need stubs.  */
+  if (spu_elf_section_data (sym_sec->output_section)->ovl_index == 0
+      && !htab->non_overlay_stubs)
+    return FALSE;
+
+  /* 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)->ovl_index
+       != spu_elf_section_data (input_section->output_section)->ovl_index)
+    return TRUE;
+
+  /* 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;
+}
+
 struct stubarr {
   struct spu_stub_hash_entry **sh;
   unsigned int count;
@@ -797,11 +831,11 @@ spu_elf_size_stubs (bfd *output_bfd,
 	      asection *sym_sec;
 	      Elf_Internal_Sym *sym;
 	      struct elf_link_hash_entry *h;
+	      const char *sym_name;
 	      char *stub_name;
 	      struct spu_stub_hash_entry *sh;
 	      unsigned int sym_type;
 	      enum _insn_type { non_branch, branch, call } insn_type;
-	      bfd_boolean is_setjmp;
 
 	      r_type = ELF32_R_TYPE (irela->r_info);
 	      r_indx = ELF32_R_SYM (irela->r_info);
@@ -847,9 +881,18 @@ spu_elf_size_stubs (bfd *output_bfd,
 
 	      /* We are only interested in function symbols.  */
 	      if (h != NULL)
-		sym_type = h->type;
+		{
+		  sym_type = h->type;
+		  sym_name = h->root.root.string;
+		}
 	      else
-		sym_type = ELF_ST_TYPE (sym->st_info);
+		{
+		  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
@@ -859,54 +902,18 @@ spu_elf_size_stubs (bfd *output_bfd,
 		     type to be correct to distinguish function pointer
 		     initialisation from other pointer initialisation.  */
 		  if (insn_type == call)
-		    {
-		      const char *sym_name;
-
-		      if (h != NULL)
-			sym_name = h->root.root.string;
-		      else
-			sym_name = bfd_elf_sym_name (sym_sec->owner,
-						     symtab_hdr,
-						     sym,
-						     sym_sec);
-
-		      (*_bfd_error_handler) (_("warning: call to non-function"
-					       " symbol %s defined in %B"),
-					     sym_sec->owner, sym_name);
-		    }
+		    (*_bfd_error_handler) (_("warning: call to non-function"
+					     " symbol %s defined in %B"),
+					   sym_sec->owner, sym_name);
 		  else
 		    continue;
 		}
 
-	      /* 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.  */
-	      is_setjmp = (h != NULL
-			   && strncmp (h->root.root.string, "setjmp", 6) == 0
-			   && (h->root.root.string[6] == '\0'
-			       || h->root.root.string[6] == '@'));
-
-	      /* Usually, non-overlay sections don't need stubs.  */
-	      if (!spu_elf_section_data (sym_sec->output_section)->ovl_index
-		  && !non_overlay_stubs
-		  && !is_setjmp)
+	      if (!needs_ovl_stub (sym_name, sym_sec, section, htab,
+				   insn_type != non_branch))
 		continue;
 
-	      /* We need a reference from some other section before
-		 we consider that a symbol might need an overlay stub.  */
-	      if (spu_elf_section_data (sym_sec->output_section)->ovl_index
-		  == spu_elf_section_data (section->output_section)->ovl_index
-		  && !is_setjmp)
-		{
-		  /* Or we need this to *not* be a branch.  ie. We are
-		     possibly taking the address of a function and
-		     passing it out somehow.  */
-		  if (insn_type != non_branch)
-		    continue;
-		}
-
-	      stub_name = spu_stub_name (section, sym_sec, h, irela);
+	      stub_name = spu_stub_name (sym_sec, h, irela);
 	      if (stub_name == NULL)
 		goto error_ret_free_internal;
 
@@ -1157,14 +1164,13 @@ write_one_stub (struct bfd_hash_entry *b
       size_t len1, len2;
       char *name;
 
-      len1 = sizeof ("ovl_call.") - 1;
+      len1 = sizeof ("00000000.ovl_call.") - 1;
       len2 = strlen (ent->root.string);
       name = bfd_malloc (len1 + len2 + 1);
       if (name == NULL)
 	return FALSE;
-      memcpy (name, ent->root.string, 9);
-      memcpy (name + 9, "ovl_call.", len1);
-      memcpy (name + 9 + len1, ent->root.string + 9, len2 - 9 + 1);
+      memcpy (name, "00000000.ovl_call.", len1);
+      memcpy (name + len1, ent->root.string, len2 + 1);
       h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
       if (h == NULL)
 	return FALSE;
@@ -1438,18 +1444,13 @@ 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 (sec != NULL
-	  && sec->output_section != NULL
-	  && sec->output_section->owner == output_bfd
-	  && (spu_elf_section_data (sec->output_section)->ovl_index != 0
-	      || htab->non_overlay_stubs)
-	  && !(sec == input_section
-	       && is_branch (contents + rel->r_offset)))
+      if (needs_ovl_stub (sym_name, sec, input_section, htab,
+			  is_branch (contents + rel->r_offset)))
 	{
 	  char *stub_name;
 	  struct spu_stub_hash_entry *sh;
 
-	  stub_name = spu_stub_name (input_section, sec, h, rel);
+	  stub_name = spu_stub_name (sec, h, rel);
 	  if (stub_name == NULL)
 	    return FALSE;
 
Index: gas/config/tc-spu.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-spu.c,v
retrieving revision 1.3
diff -u -p -r1.3 tc-spu.c
--- gas/config/tc-spu.c	24 Nov 2006 04:32:41 -0000	1.3
+++ gas/config/tc-spu.c	22 Mar 2007 22:03:56 -0000
@@ -22,7 +22,6 @@
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
-#include "opcode/spu.h"
 #include "dwarf2dbg.h" 
 
 const struct spu_opcode spu_opcodes[] = {
@@ -366,7 +365,8 @@ md_assemble (char *op)
 			    &insn.exp[i],
 			    pcrel,
 			    reloc);
-	fixP->tc_fix_data = insn.reloc_arg[i];
+	fixP->tc_fix_data.arg_format = insn.reloc_arg[i];
+	fixP->tc_fix_data.insn_tag = insn.tag;
       }
   dwarf2_emit_insn (4);
 }
@@ -941,10 +941,10 @@ md_apply_fix (fixS *fixP, valueT *valP, 
     {
       fixP->fx_done = 1;
       res = 0;
-      if (fixP->tc_fix_data > A_P)
+      if (fixP->tc_fix_data.arg_format > A_P)
 	{
-	  int hi = arg_encode[fixP->tc_fix_data].hi;
-	  int lo = arg_encode[fixP->tc_fix_data].lo;
+	  int hi = arg_encode[fixP->tc_fix_data.arg_format].hi;
+	  int lo = arg_encode[fixP->tc_fix_data.arg_format].lo;
 	  if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi))
 	    as_bad_where (fixP->fx_file, fixP->fx_line,
 			  "Relocation doesn't fit. (relocation value = 0x%lx)",
Index: gas/config/tc-spu.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-spu.h,v
retrieving revision 1.2
diff -u -p -r1.2 tc-spu.h
--- gas/config/tc-spu.h	12 Jan 2007 06:23:52 -0000	1.2
+++ gas/config/tc-spu.h	22 Mar 2007 22:03:56 -0000
@@ -21,6 +21,8 @@
 
 #define TC_SPU
 
+#include "opcode/spu.h"
+
 #ifdef OBJ_ELF
 #define TARGET_FORMAT "elf32-spu"
 #define TARGET_ARCH bfd_arch_spu
@@ -44,13 +46,35 @@
 #define TC_KEEP_FX_OFFSET
 /* #define TC_CONS_RELOC RELOC_32 */
 
-/* If defined, fixS will have a member named tc_fix_data of this type.  */
-#define TC_FIX_TYPE int
-#define TC_INIT_FIX_DATA(FIXP) ((FIXP)->tc_fix_data = 0)
+struct tc_fix_info {
+  unsigned short arg_format;
+  unsigned short insn_tag;
+};
+
+/* fixS will have a member named tc_fix_data of this type.  */
+#define TC_FIX_TYPE struct tc_fix_info
+#define TC_INIT_FIX_DATA(FIXP) \
+  do						\
+    {						\
+      (FIXP)->tc_fix_data.arg_format = 0;	\
+      (FIXP)->tc_fix_data.insn_tag = 0;		\
+    }						\
+  while (0)
 
 /* Don't reduce function symbols to section symbols.  */
 #define tc_fix_adjustable(FIXP) (!S_IS_FUNCTION ((FIXP)->fx_addsy))
 
+/* Keep relocs on calls.  Branches to function symbols are tail or
+   sibling calls.  */
+#define TC_FORCE_RELOCATION(FIXP) \
+  ((FIXP)->tc_fix_data.insn_tag == M_BRSL		\
+   || (FIXP)->tc_fix_data.insn_tag == M_BRASL		\
+   || (((FIXP)->tc_fix_data.insn_tag == M_BR		\
+	|| (FIXP)->tc_fix_data.insn_tag == M_BRA)	\
+       && (FIXP)->fx_addsy != NULL			\
+       && S_IS_FUNCTION ((FIXP)->fx_addsy))		\
+   || generic_force_reloc (FIXP))
+
 /* Values passed to md_apply_fix don't include symbol values.  */
 #define MD_APPLY_SYM_VALUE(FIX) 0
 
Index: ld/testsuite/ld-spu/ovl.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-spu/ovl.d,v
retrieving revision 1.1
diff -u -p -r1.1 ovl.d
--- ld/testsuite/ld-spu/ovl.d	25 Oct 2006 06:49:21 -0000	1.1
+++ ld/testsuite/ld-spu/ovl.d	22 Mar 2007 08:03:20 -0000
@@ -1,6 +1,6 @@
 #source: ovl.s
-#ld: -N -T ovl.lnk
-#objdump: -D
+#ld: -N -T ovl.lnk --emit-relocs
+#objdump: -D -r
 
 .*elf32-spu
 
@@ -11,28 +11,39 @@ Disassembly of section \.text:
  104:	48 20 00 00 	xor	\$0,\$0,\$0
  108:	24 00 00 80 	stqd	\$0,0\(\$1\)
  10c:	24 00 40 80 	stqd	\$0,16\(\$1\)
- 110:	33 00 04 00 	brsl	\$0,130 <f0\+0x4>	# 130
- 114:	33 00 04 80 	brsl	\$0,138 <f0\+0xc>	# 138
- 118:	33 00 07 00 	brsl	\$0,150 <f0\+0x24>	# 150
+ 110:	33 00 04 00 	brsl	\$0,130 <00000000\.ovl_call\.f1_a1>	# 130
+			110: SPU_REL16	f1_a1
+ 114:	33 00 04 80 	brsl	\$0,138 <00000000\.ovl_call\.f2_a1>	# 138
+			114: SPU_REL16	f2_a1
+ 118:	33 00 07 00 	brsl	\$0,150 <00000000\.ovl_call\.f1_a2>	# 150
+			118: SPU_REL16	f1_a2
  11c:	42 00 ac 09 	ila	\$9,344	# 158
+			11c: SPU_ADDR18	f2_a2
  120:	35 20 04 80 	bisl	\$0,\$9
  124:	1c 08 00 81 	ai	\$1,\$1,32	# 20
  128:	32 7f fb 00 	br	100 <_start>	# 100
+			128: SPU_REL16	_start
 
 0000012c <f0>:
  12c:	35 00 00 00 	bi	\$0
+00000130 <00000000\.ovl_call\.f1_a1>:
  130:	42 02 00 4f 	ila	\$79,1024	# 400
- 134:	32 00 02 80 	br	148 <f0\+0x1c>	# 148
+ 134:	32 00 02 80 	br	148 .*
+00000138 <00000000\.ovl_call\.f2_a1>:
  138:	42 02 02 4f 	ila	\$79,1028	# 404
- 13c:	32 00 01 80 	br	148 <f0\+0x1c>	# 148
+ 13c:	32 00 01 80 	br	148 .*
+00000140 <00000000\.ovl_call\.f4_a1>:
  140:	42 02 08 4f 	ila	\$79,1040	# 410
  144:	40 20 00 00 	nop	\$0
  148:	42 00 00 ce 	ila	\$78,1
  14c:	32 00 0a 80 	br	1a0 <__ovly_load>	# 1a0
+00000150 <00000000\.ovl_call\.f1_a2>:
  150:	42 02 00 4f 	ila	\$79,1024	# 400
- 154:	32 00 02 80 	br	168 <f0\+0x3c>	# 168
+ 154:	32 00 02 80 	br	168 .*
+00000158 <00000000\.ovl_call\.f2_a2>:
  158:	42 02 12 4f 	ila	\$79,1060	# 424
- 15c:	32 00 01 80 	br	168 <f0\+0x3c>	# 168
+ 15c:	32 00 01 80 	br	168 .*
+00000160 <00000000\.ovl_call\.14:8>:
  160:	42 02 1a 4f 	ila	\$79,1076	# 434
  164:	40 20 00 00 	nop	\$0
  168:	42 00 01 4e 	ila	\$78,2
@@ -51,9 +62,11 @@ Disassembly of section \.ov_a1:
 
 00000400 <f1_a1>:
  400:	32 00 01 80 	br	40c <f3_a1>	# 40c
+			400: SPU_REL16	f3_a1
 
 00000404 <f2_a1>:
  404:	42 00 a0 03 	ila	\$3,320	# 140
+			404: SPU_ADDR18	f4_a1
  408:	35 00 00 00 	bi	\$0
 
 0000040c <f3_a1>:
@@ -69,22 +82,28 @@ Disassembly of section \.ov_a2:
  404:	24 ff 80 81 	stqd	\$1,-32\(\$1\)
  408:	1c f8 00 81 	ai	\$1,\$1,-32
  40c:	33 7f a4 00 	brsl	\$0,12c <f0>	# 12c
- 410:	33 7f a4 00 	brsl	\$0,130 <f0\+0x4>	# 130
+			40c: SPU_REL16	f0
+ 410:	33 7f a4 00 	brsl	\$0,130 <00000000\.ovl_call\.f1_a1>	# 130
+			410: SPU_REL16	f1_a1
  414:	33 00 03 80 	brsl	\$0,430 <f3_a2>	# 430
+			414: SPU_REL16	f3_a2
  418:	34 00 c0 80 	lqd	\$0,48\(\$1\)	# 30
  41c:	1c 08 00 81 	ai	\$1,\$1,32	# 20
  420:	35 00 00 00 	bi	\$0
 
 00000424 <f2_a2>:
  424:	41 00 00 03 	ilhu	\$3,0
+			424: SPU_ADDR16_HI	f4_a2
  428:	60 80 b0 03 	iohl	\$3,352	# 160
+			428: SPU_ADDR16_LO	f4_a2
  42c:	35 00 00 00 	bi	\$0
 
 00000430 <f3_a2>:
  430:	35 00 00 00 	bi	\$0
 
 00000434 <f4_a2>:
- 434:	35 00 00 00 	bi	\$0
+ 434:	32 7f ff 80 	br	430 <f3_a2>	# 430
+			434: SPU_REL16	f3_a2
 	\.\.\.
 Disassembly of section .data:
 
Index: ld/testsuite/ld-spu/ovl.s
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-spu/ovl.s,v
retrieving revision 1.1
diff -u -p -r1.1 ovl.s
--- ld/testsuite/ld-spu/ovl.s	25 Oct 2006 06:49:21 -0000	1.1
+++ ld/testsuite/ld-spu/ovl.s	22 Mar 2007 08:03:20 -0000
@@ -78,5 +78,5 @@ f3_a2:
 
  .type f4_a2,@function
 f4_a2:
- bi lr
+ br f3_a2
  .size f4_a2,.-f4_a2

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]