ARM branches to absolute addresses

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

ARM branches to absolute addresses

Paul Brook
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  <[hidden email]>
        Nathan Sidwell  <[hidden email]>

        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