Subject: bfd and gas patch for sh3 REL32 (Re: Self build error)
To: None <thorpej@wasabisystems.com>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-dreamcast
Date: 02/04/2003 23:41:55
In article <200301261823.h0QINEM28634@mirage.ceres.dti.ne.jp> on port-dreamcast
I wrote:

> In article <200301242232.h0OMWg800801@mirage.ceres.dti.ne.jp>
> I wrote:
> 
> > In article <20030124215106.GB8538@yeah-baby.shagadelic.org>
> > thorpej@wasabisystems.com wrote:
> > 
> > > On Sat, Jan 25, 2003 at 05:45:27AM +0900, Izumi Tsutsui wrote:
> > >  > The following patch seems to fix the problem.
> > >  > (though I don't know gas statements..)
> > > 
> > > I'm a little confused as to why the globl is needed ... it's supposed
> > > to be calling a non-global (static) function...
> > 
> > I know all functions used in the macro declared as static, but
> > without .globl, MD_CALL_STATIC_FUNCTION(.init, __do_global_[cd]tors_aux)
> > jumps __ctors() (first function?), not __do_global_[cd]tors_aux().
> 
> It seems SH bfd relocation bug. I applied the following diff:
> http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/bfd/elf32-sh.c.diff?r1=1.35&r2=1.36&cvsroot=src
> to toolchain/bfd/elf32-sh.c, and it changes the behavoir a bit,
> but it still sets wrong address.

Applying the above patch to bfd and also taking a patch
against gas/config/tc-sh.c from kaz Kojima's gnu-on-sh page
http://dodo.nurs.or.jp/~kkojima/gnu-on-sh/
seems to fix the problem..
---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp

Index: bfd/elf32-sh.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/bfd/elf32-sh.c,v
retrieving revision 1.4
diff -u -r1.4 elf32-sh.c
--- bfd/elf32-sh.c	2001/08/14 04:43:07	1.4
+++ bfd/elf32-sh.c	2003/02/04 14:36:19
@@ -121,8 +121,8 @@
 	 complain_overflow_signed, /* complain_on_overflow */
 	 sh_elf_ignore_reloc,	/* special_function */
 	 "R_SH_REL32",		/* name */
-	 false,			/* partial_inplace */
-	 0,			/* src_mask */
+	 true,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
 	 0xffffffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
@@ -2917,8 +2917,12 @@
 	}
 
       howto = sh_elf_howto_table + r_type;
+
+      /* For relocs that aren't partial_inplace, we get the addend from
+         the relocation.  */
+      if (! howto->partial_inplace)
+	addend = rel->r_addend;
 
-      /* This is a final link.  */
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -2938,7 +2942,32 @@
 		 section symbol winds up in the output section.  */
 	      sym = local_syms + r_symndx;
 	      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-		goto final_link_relocate;
+		{
+		  if (! howto->partial_inplace)
+		    {
+		      /* For relocations with the addend in the
+			 relocation, we need just to update the addend.
+			 All real relocs are of type partial_inplace; this
+			 code is mostly for completeness.  */
+		      rel->r_addend += sec->output_offset + sym->st_value;
+
+		      continue;
+		    }
+
+		  /* Relocs of type partial_inplace need to pick up the
+		     contents in the contents and add the offset resulting
+		     from the changed location of the section symbol.
+		     Using _bfd_final_link_relocate (e.g. goto
+		     final_link_relocate) here would be wrong, because
+		     relocations marked pc_relative would get the current
+		     location subtracted, and we must only do that at the
+		     final link.  */
+		  r = _bfd_relocate_contents (howto, input_bfd,
+					      sec->output_offset
+					      + sym->st_value,
+					      contents + rel->r_offset);
+		  goto relocation_done;
+		}
 
 	      continue;
 	    }
@@ -3111,7 +3140,8 @@
 		  BFD_ASSERT (h != NULL && h->dynindx != -1);
 		  relocate = false;
 		  outrel.r_info = ELF32_R_INFO (h->dynindx, R_SH_REL32);
-		  outrel.r_addend = rel->r_addend;
+		  outrel.r_addend
+		    = bfd_get_32 (input_bfd, contents + rel->r_offset);
 		}
 	      else
 		{
@@ -3124,14 +3154,18 @@
 		    {
 		      relocate = true;
 		      outrel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
-		      outrel.r_addend = relocation + rel->r_addend;
+		      outrel.r_addend
+			= relocation + bfd_get_32 (input_bfd,
+						   contents + rel->r_offset);
 		    }
 		  else
 		    {
 		      BFD_ASSERT (h->dynindx != -1);
 		      relocate = false;
 		      outrel.r_info = ELF32_R_INFO (h->dynindx, R_SH_DIR32);
-		      outrel.r_addend = relocation + rel->r_addend;
+		      outrel.r_addend
+			= relocation + bfd_get_32 (input_bfd,
+						   contents + rel->r_offset);
 		    }
 		}
 
@@ -3148,8 +3182,6 @@
 	      if (! relocate)
 		continue;
 	    }
-	  else if (r_type == R_SH_DIR32)
-	    addend = rel->r_addend;
 	  goto final_link_relocate;
 
 	case R_SH_GOT32:
@@ -3329,6 +3361,7 @@
 	  }
 	}
 
+    relocation_done:
       if (r != bfd_reloc_ok)
 	{
 	  switch (r)
Index: gas/config/tc-sh.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gas/config/tc-sh.c,v
retrieving revision 1.3
diff -u -r1.3 tc-sh.c
--- gas/config/tc-sh.c	2002/04/10 11:33:06	1.3
+++ gas/config/tc-sh.c	2003/02/04 14:36:23
@@ -2852,6 +2852,11 @@
       && fixP->fx_addsy != NULL
       && S_IS_WEAK (fixP->fx_addsy))
     val -= S_GET_VALUE  (fixP->fx_addsy);
+
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+      && fixP->fx_r_type == BFD_RELOC_32_PCREL
+      && fixP->fx_addsy != NULL)
+    val += fixP->fx_where + fixP->fx_frag->fr_address;
 #endif
 
 #ifndef BFD_ASSEMBLER