bfd and gas patch for sh3 REL32 (Re: Self build error)

Izumi Tsutsui <[email protected]>
Newsgroups gmane.os.netbsd.ports.sh3,gmane.os.netbsd.ports.dreamcast
Message-ID <[email protected]>
In article <[email protected]> on port-dreamcast
I wrote:

> In article <[email protected]>
> I wrote:
> 
> > In article <[email protected]>
> > [email protected] 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
[email protected]

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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.