[RFA] ARM OABI - pc-relative relocations

Zack Weinberg zack@codesourcery.com
Mon Dec 15 16:50:00 GMT 2003


Jerome Guitton <guitton@act-europe.fr> writes:

> Ouch! That is perfectly reasonable, but I have a problem. I am
> targetting VxWorks 5.5 on ARM. WRS' tools uses RELA, with the old ABI
> definition... And I am interested in making a the GNU tools and WRS
> tools compatible.

I already have patches for this.  They are not quite suitable for
inclusion, but I think only small changes would be required.  Also I
am not sure they solve your problem.  What I did was hack up BFD to
produce RELA relocs for ARM, and then I modified GAS so that in
RELA/arm mode it always sets the instruction addend to zero.  The
linker then need not know or care about the quirky old-ABI spec for
RELA.  Conveniently, this is what WRS' tools do, too.

Patch is appended.  Comments?  I do not know the proper way to get
USE_REL set to 0; obviously "#ifndef NOT_VXWORKS" is not the right
approach.

zw

        * bfd/elfarm-nabi.c: Force USE_REL to 0.
        * bfd/elf32-arm.h (elf32_arm_final_link_relocate): Do not adjust
        RELA addends by howto->size.
        * gas/config/tc-arm.c: If a fixup will produce a relocation in
        the final object file, and RELA relocations are used for this
        segment, then don't put the addend in the instruction stream;
        instead correct fixP->fx_offset and/or fixP->fx_addnumber as
        necessary.

===================================================================
Index: bfd/elfarm-nabi.c
--- bfd/elfarm-nabi.c	2 Sep 2003 23:49:48 -0000	1.1.3.1
+++ bfd/elfarm-nabi.c	1 Dec 2003 08:00:23 -0000	1.1.3.1.2.1
@@ -27,7 +27,12 @@
 #define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
 #endif
 
+/* WRS LOCAL - force use of RELA */
+#ifndef NOT_VXWORKS
+#define USE_REL 0 /* affirmative setting to catch others */
+#else
 #define USE_REL	1
+#endif
 
 #define TARGET_LITTLE_SYM               bfd_elf32_littlearm_vec
 #define TARGET_LITTLE_NAME              "elf32-littlearm"
===================================================================
Index: bfd/elf32-arm.h
--- bfd/elf32-arm.h	26 Nov 2003 05:09:51 -0000	1.1.3.1.2.1
+++ bfd/elf32-arm.h	1 Dec 2003 08:00:22 -0000	1.1.3.1.2.2
@@ -1458,7 +1458,12 @@ elf32_arm_final_link_relocate (howto, in
 	      value -= (input_section->output_section->vma
 			+ input_section->output_offset);
 	      value -= rel->r_offset;
+#if USE_REL
 	      value += (signed_addend << howto->size);
+#else
+	      /* RELA addends do not have to be adjusted by howto->size.  */
+	      value += signed_addend;
+#endif
 
 	      /* Previous versions of this code also used to add in the pipeline
 		 offset here.  This is wrong because the linker is not supposed
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c	26 Nov 2003 05:10:06 -0000	1.1.3.1.2.1
+++ gas/config/tc-arm.c	1 Dec 2003 08:00:23 -0000	1.1.3.1.2.2
@@ -11274,7 +11274,19 @@ md_apply_fix3 (fixP, valP, seg)
 	as_bad_where (fixP->fx_file, fixP->fx_line,
 		      _("out of range branch"));
 
-      newval = (value & 0x00ffffff) | (newval & 0xff000000);
+      if (seg->use_rela_p && !fixP->fx_done)
+	{
+	  /* Must unshift the value before storing it in the addend.  */
+	  value <<= 2;
+#ifdef OBJ_ELF
+	  if (! target_oabi)
+	    fixP->fx_offset = value;
+#endif
+	  fixP->fx_addnumber = value;
+	  newval = newval & 0xff000000;
+	}
+      else
+	  newval = (value & 0x00ffffff) | (newval & 0xff000000);
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
@@ -11290,7 +11302,22 @@ md_apply_fix3 (fixP, valP, seg)
 	hbit   = (value >> 1) & 1;
 	value  = (value >> 2) & 0x00ffffff;
 	value  = (value + (newval & 0x00ffffff)) & 0x00ffffff;
-	newval = value | (newval & 0xfe000000) | (hbit << 24);
+
+	if (seg->use_rela_p && !fixP->fx_done)
+	  {
+	    /* Must sign-extend and unshift the value before storing
+	       it in the addend.  */
+	    value = SEXT24 (value);
+	    value = (value << 2) | hbit;
+#ifdef OBJ_ELF
+	    if (! target_oabi)
+	      fixP->fx_offset = value;
+#endif
+	    fixP->fx_addnumber = value;
+	    newval = newval & 0xfe000000;
+	  }
+	else
+	  newval = value | (newval & 0xfe000000) | (hbit << 24);
 	md_number_to_chars (buf, newval, INSN_SIZE);
       }
       break;
@@ -11306,7 +11333,17 @@ md_apply_fix3 (fixP, valP, seg)
 	if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
 	  as_bad_where (fixP->fx_file, fixP->fx_line,
 			_("branch out of range"));
-	newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
+	if (seg->use_rela_p && !fixP->fx_done)
+	  {
+#ifdef OBJ_ELF
+	    if (! target_oabi)
+	      fixP->fx_offset = value;
+#endif
+	    fixP->fx_addnumber = value;
+	    newval = newval & 0xff00;
+	  }
+	else
+	  newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
       }
       md_number_to_chars (buf, newval, THUMB_SIZE);
       break;
@@ -11322,7 +11359,17 @@ md_apply_fix3 (fixP, valP, seg)
 	if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
 	  as_bad_where (fixP->fx_file, fixP->fx_line,
 			_("branch out of range"));
-	newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
+	if (seg->use_rela_p && !fixP->fx_done)
+	  {
+#ifdef OBJ_ELF
+	    if (! target_oabi)
+	      fixP->fx_offset = value;
+#endif
+	    fixP->fx_addnumber = value;
+	    newval = newval & 0xf800;
+	  }
+	else
+	  newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
       }
       md_number_to_chars (buf, newval, THUMB_SIZE);
       break;
@@ -11347,20 +11394,36 @@ md_apply_fix3 (fixP, valP, seg)
 	  as_bad_where (fixP->fx_file, fixP->fx_line,
 			_("branch with link out of range"));
 
-	newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
-	newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
 	if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
 	  /* For a BLX instruction, make sure that the relocation is rounded up
 	     to a word boundary.  This follows the semantics of the instruction
 	     which specifies that bit 1 of the target address will come from bit
 	     1 of the base address.  */
-	  newval2 = (newval2 + 1) & ~ 1;
+	  value = (value + 1) & ~ 1;
+
+	if (seg->use_rela_p && !fixP->fx_done)
+	  {
+#ifdef OBJ_ELF
+	    if (! target_oabi)
+	      fixP->fx_offset = value;
+#endif
+	    fixP->fx_addnumber = value;
+	    newval = newval & 0xf800;
+	    newval2 = newval2 & 0xf800;
+	  }
+	else
+	  {
+	    newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
+	    newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+	  }
 	md_number_to_chars (buf, newval, THUMB_SIZE);
 	md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
       }
       break;
 
     case BFD_RELOC_8:
+      if (seg->use_rela_p && !fixP->fx_done)
+	break;
       if (fixP->fx_done || fixP->fx_pcrel)
 	md_number_to_chars (buf, value, 1);
 #ifdef OBJ_ELF
@@ -11373,6 +11436,8 @@ md_apply_fix3 (fixP, valP, seg)
       break;
 
     case BFD_RELOC_16:
+      if (seg->use_rela_p && !fixP->fx_done)
+	break;
       if (fixP->fx_done || fixP->fx_pcrel)
 	md_number_to_chars (buf, value, 2);
 #ifdef OBJ_ELF
@@ -11387,12 +11452,16 @@ md_apply_fix3 (fixP, valP, seg)
 #ifdef OBJ_ELF
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
+      if (seg->use_rela_p && !fixP->fx_done)
+	break;
       md_number_to_chars (buf, 0, 4);
       break;
 #endif
 
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
+      if (seg->use_rela_p && !fixP->fx_done)
+	break;
       if (fixP->fx_done || fixP->fx_pcrel)
 	md_number_to_chars (buf, value, 4);
 #ifdef OBJ_ELF



More information about the Binutils mailing list