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]

ARM branches to absolute addresses


The attached patch fixes generation of branches to absolute addresses.  
Currently we emit these as relocations against symbol index 0.  This isn't a 
problem in itself, however it causes a couple of subsequent issues.  Firstly 
gas gets confused and adjusts the addend by the offset of the current 
instruction.  Secondly REL branch relocations have limited range, so only a 
subset of addresses can be encoded.

The attached patch fixes this by creating an absolute symbol at the desired 
address and emitting relocations against that.

As mentioned in the comment, this still isn't completely correct.  When the 
address comes from a .set directive we should be referencing the symbol the 
user specified.  Unfortunately the expression parser/folder doesn't obey 
TC_FORCE_RELOCATION etc., so has already eaten the original symbol before we 
have chance to handle this.  In practice using the bare value is close enough 
for most real uses, and strictly better than what we had before.

Tested on arm-none-eabi
Applied to CVS head

2011-05-31  Paul Brook  <paul@codesourcery.com>
	Nathan Sidwell  <nathan@codesourcery.com>

	gas/
	* config/tc-arm.c (fix_new_arm): Create an absolute symbol for
	pc-relative fixes to constants.
	* config/tc-arm.h (TC_FORCE_RELOCATATION_ABS): Define.
	
	ld/testsuite/
	* ld-arm/abs-call-1.d: New.
	* ld-arm/abs-call-1.s: New.
	* ld-arm/arm-elf.exp: Add it.
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index a9839cd..375ff82 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -15434,6 +15434,29 @@ fix_new_arm (fragS *	   frag,
   switch (exp->X_op)
     {
     case O_constant:
+      if (pc_rel)
+	{
+	  /* Create an absolute valued symbol, so we have something to
+             refer to in the object file.  Unfortunately for us, gas's
+             generic expression parsing will already have folded out
+             any use of .set foo/.type foo %function that may have
+             been used to set type information of the target location,
+             that's being specified symbolically.  We have to presume
+             the user knows what they are doing.  */
+	  char name[16 + 8];
+	  symbolS *symbol;
+
+	  sprintf (name, "*ABS*0x%lx", (unsigned long)exp->X_add_number);
+
+	  symbol = symbol_find_or_make (name);
+	  S_SET_SEGMENT (symbol, absolute_section);
+	  symbol_set_frag (symbol, &zero_address_frag);
+	  S_SET_VALUE (symbol, exp->X_add_number);
+	  exp->X_op = O_symbol;
+	  exp->X_add_symbol = symbol;
+	  exp->X_add_number = 0;
+	}
+      /* FALLTHROUGH */
     case O_symbol:
     case O_add:
     case O_subtract:
diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h
index 702e405..2916ae1 100644
--- a/gas/config/tc-arm.h
+++ b/gas/config/tc-arm.h
@@ -192,6 +192,12 @@ void arm_copy_symbol_attributes (symbolS *, symbolS *);
   (THUMB_IS_FUNC ((FIX)->fx_addsy)		\
    || !SEG_NORMAL (SEG))
 
+#define TC_FORCE_RELOCATION_ABS(FIX)			\
+  (((FIX)->fx_pcrel					\
+    && (FIX)->fx_r_type != BFD_RELOC_32			\
+    && (FIX)->fx_r_type != BFD_RELOC_ARM_GOT32)		\
+   || TC_FORCE_RELOCATION(FIX))
+
 #define TC_CONS_FIX_NEW cons_fix_new_arm
 
 #define MAX_MEM_ALIGNMENT_BYTES    6
diff --git a/ld/testsuite/ld-arm/abs-call-1.d b/ld/testsuite/ld-arm/abs-call-1.d
new file mode 100644
index 0000000..4482beb
--- /dev/null
+++ b/ld/testsuite/ld-arm/abs-call-1.d
@@ -0,0 +1,9 @@
+.*:     file format elf32-.*
+
+
+Disassembly of section .text:
+
+00008000 <arm>:
+    8000:	eb03dffe 	bl	100000 <foo>
+    8004:	ea03dffd 	b	100000 <foo>
+    8008:	eb03dffc 	bl	100000 <foo>
diff --git a/ld/testsuite/ld-arm/abs-call-1.s b/ld/testsuite/ld-arm/abs-call-1.s
new file mode 100644
index 0000000..c0a66b4
--- /dev/null
+++ b/ld/testsuite/ld-arm/abs-call-1.s
@@ -0,0 +1,8 @@
+
+	.type foo, %function
+	.set foo, 0x100000
+
+arm:	bl	0x100000
+	b	0x100000
+	bl	foo
+
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 95959f8..a8c51c2 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -413,6 +413,9 @@ set armelftests {
       {objdump {-s -j.data -j.got} ifunc-16.gd}
       {readelf -r ifunc-16.rd}}
      "ifunc-16"}
+    {"abs call" "-T arm.ld" "" {abs-call-1.s}
+     {{objdump -d abs-call-1.d}}
+     "abs-call-1"}
 }
 
 run_ld_link_tests $armelftests

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