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]

[commit, spu] Handle non-branch relocs when building call graph


Hello,

when using a software i-cache compiler on the SPU that splits functions up into
multiple sections, the linker currently may not always recognize all part of that
function.  The unrecognized sections will then be treated as "pasted" sections
(like .init) that must join the preceding section.  This can cause suboptimal
placement decisions or even cache line overflows.

The reason why sections may not be recognized as part of a function is that
mark_functions_via_relocs currently does not handle relocations on anything
but branch instructions.  This means that parts of function code that are
reachable only via a code label reference from anything but a branch (e.g.
jump table entries or other references to load a code label as data) will
be ignored.

The following patch fixes this problem by handling such references as well.
Note that while they must contribute to the call graph, they do not require
stubs to be generated in the software i-cache case; this is reflected by
setting the call_info.count field to zero for these cases.

Tested with no regressions on spu-elf on mainline and the 2_20 branch.
Approved off-line by Alan Modra; committed to mainline and branch.

Bye,
Ulrich


2009-11-03  Alan Modra  <amodra@bigpond.net.au>
	    Ulrich Weigand  <uweigand@de.ibm.com>

	* elf32-spu.c (mark_functions_via_relocs): Handle non-branch relocs
	(jump tables or other references to code labels) as well.

diff -urNp src.orig/bfd/elf32-spu.c src/bfd/elf32-spu.c
--- src.orig/bfd/elf32-spu.c	2009-11-02 16:26:03.000000000 +0100
+++ src/bfd/elf32-spu.c	2009-11-02 16:33:56.000000000 +0100
@@ -2670,19 +2670,12 @@ mark_functions_via_relocs (asection *sec
       Elf_Internal_Sym *sym;
       struct elf_link_hash_entry *h;
       bfd_vma val;
-      bfd_boolean reject, is_call;
+      bfd_boolean nonbranch, is_call;
       struct function_info *caller;
       struct call_info *callee;
 
-      reject = FALSE;
       r_type = ELF32_R_TYPE (irela->r_info);
-      if (r_type != R_SPU_REL16
-	  && r_type != R_SPU_ADDR16)
-	{
-	  reject = TRUE;
-	  if (!(call_tree && spu_hash_table (info)->params->auto_overlay))
-	    continue;
-	}
+      nonbranch = r_type != R_SPU_REL16 && r_type != R_SPU_ADDR16;
 
       r_indx = ELF32_R_SYM (irela->r_info);
       if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, sec->owner))
@@ -2693,7 +2686,7 @@ mark_functions_via_relocs (asection *sec
 	continue;
 
       is_call = FALSE;
-      if (!reject)
+      if (!nonbranch)
 	{
 	  unsigned char insn[4];
 
@@ -2724,14 +2717,13 @@ mark_functions_via_relocs (asection *sec
 	    }
 	  else
 	    {
-	      reject = TRUE;
-	      if (!(call_tree && spu_hash_table (info)->params->auto_overlay)
-		  || is_hint (insn))
+	      nonbranch = TRUE;
+	      if (is_hint (insn))
 		continue;
 	    }
 	}
 
-      if (reject)
+      if (nonbranch)
 	{
 	  /* For --auto-overlay, count possible stubs we need for
 	     function pointer references.  */
@@ -2741,8 +2733,20 @@ mark_functions_via_relocs (asection *sec
 	  else
 	    sym_type = ELF_ST_TYPE (sym->st_info);
 	  if (sym_type == STT_FUNC)
-	    spu_hash_table (info)->non_ovly_stub += 1;
-	  continue;
+	    {
+	      if (call_tree && spu_hash_table (info)->params->auto_overlay)
+		spu_hash_table (info)->non_ovly_stub += 1;
+	      /* If the symbol type is STT_FUNC then this must be a
+		 function pointer initialisation.  */
+	      continue;
+	    }
+	  /* Ignore data references.  */
+	  if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE))
+	      != (SEC_ALLOC | SEC_LOAD | SEC_CODE))
+	    continue;
+	  /* Otherwise we probably have a jump table reloc for
+	     a switch statement or some other reference to a
+	     code label.  */
 	}
 
       if (h)
@@ -2791,7 +2795,7 @@ mark_functions_via_relocs (asection *sec
       callee->is_pasted = FALSE;
       callee->broken_cycle = FALSE;
       callee->priority = priority;
-      callee->count = 1;
+      callee->count = nonbranch? 0 : 1;
       if (callee->fun->last_caller != sec)
 	{
 	  callee->fun->last_caller = sec;
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


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